variant.cpp

Go to the documentation of this file.
00001 #include "global.hpp"
00002 
00003 #include <cmath>
00004 #include <set>
00005 #include <stdlib.h>
00006 #include <iostream>
00007 #include <string.h>
00008 
00009 #include "boost/lexical_cast.hpp"
00010 
00011 //#include "foreach.hpp"
00012 #include "formatter.hpp"
00013 #include "formula.hpp"
00014 #include "formula_callable.hpp"
00015 #include "variant.hpp"
00016 
00017 namespace {
00018 std::string variant_type_to_string(variant::TYPE type) {
00019     switch(type) {
00020     case variant::TYPE_NULL: 
00021         return "null";
00022     case variant::TYPE_INT: 
00023         return "int";
00024     case variant::TYPE_CALLABLE: 
00025         return "object";
00026     case variant::TYPE_LIST: 
00027         return "list";
00028     case variant::TYPE_STRING: 
00029         return "string";
00030     case variant::TYPE_MAP: 
00031         return "map";
00032     default:
00033         assert(false);
00034         return "invalid";
00035     }
00036 }
00037 
00038 std::vector<const char*> call_stack;
00039 }
00040 
00041 void push_call_stack(const char* str)
00042 {
00043     call_stack.push_back(str);
00044 }
00045 
00046 void pop_call_stack()
00047 {
00048     call_stack.pop_back();
00049 }
00050 
00051 std::string get_call_stack()
00052 {
00053     std::string res;
00054     for(std::vector<const char*>::const_iterator i = call_stack.begin();
00055         i != call_stack.end(); ++i) {
00056         if(!*i) {
00057             continue;
00058         }
00059         res += "  ";
00060         res += *i;
00061         res += "\n";
00062     }
00063     return res;
00064 }
00065 
00066 type_error::type_error(const std::string& str) : message(str) {
00067     std::cerr << "ERROR: " << message << "\n" << get_call_stack();
00068 }
00069 
00070 struct variant_list {
00071     variant_list() : refcount(0)
00072     {}
00073     std::vector<variant> elements;
00074     int refcount;
00075 };
00076 
00077 struct variant_string {
00078     variant_string() : refcount(0)
00079     {}
00080     std::string str;
00081     int refcount;
00082 };
00083 
00084 struct variant_map {
00085     variant_map() : refcount(0)
00086     {}
00087     std::map<variant,variant> elements;
00088     int refcount;
00089 };
00090 
00091 void variant::increment_refcount()
00092 {
00093     switch(type_) {
00094     case TYPE_LIST:
00095         ++list_->refcount;
00096         break;
00097     case TYPE_STRING:
00098         ++string_->refcount;
00099         break;
00100     case TYPE_MAP:
00101         ++map_->refcount;
00102         break;
00103     case TYPE_CALLABLE:
00104         intrusive_ptr_add_ref(callable_);
00105         break;
00106 
00107     // These are not used here, add them to silence a compiler warning.
00108     case TYPE_NULL:
00109     case TYPE_INT :
00110         break;
00111     }
00112 }
00113 
00114 void variant::release()
00115 {
00116     switch(type_) {
00117     case TYPE_LIST:
00118         if(--list_->refcount == 0) {
00119             delete list_;
00120         }
00121         break;
00122     case TYPE_STRING:
00123         if(--string_->refcount == 0) {
00124             delete string_;
00125         }
00126         break;
00127     case TYPE_MAP:
00128         if(--map_->refcount == 0) {
00129             delete map_;
00130         }
00131         break;
00132     case TYPE_CALLABLE:
00133         intrusive_ptr_release(callable_);
00134         break;
00135 
00136     // These are not used here, add them to silence a compiler warning.
00137     case TYPE_NULL:
00138     case TYPE_INT :
00139         break;
00140     }
00141 }
00142 
00143 variant::variant() : type_(TYPE_NULL), int_value_(0)
00144 {}
00145 
00146 variant::variant(int n) : type_(TYPE_INT), int_value_(n)
00147 {}
00148 
00149 variant::variant(const game_logic::formula_callable* callable)
00150     : type_(TYPE_CALLABLE), callable_(callable)
00151 {
00152     assert(callable_);
00153     increment_refcount();
00154 }
00155 
00156 variant::variant(std::vector<variant>* array)
00157     : type_(TYPE_LIST)
00158 {
00159     assert(array);
00160     list_ = new variant_list;
00161     list_->elements.swap(*array);
00162     increment_refcount();
00163 }
00164 
00165 variant::variant(const std::string& str)
00166     : type_(TYPE_STRING)
00167 {
00168     string_ = new variant_string;
00169     string_->str = str;
00170     increment_refcount();
00171 }
00172 
00173 variant::variant(std::map<variant,variant>* map)
00174     : type_(TYPE_MAP)
00175 {
00176     assert(map);
00177     map_ = new variant_map;
00178     map_->elements.swap(*map);
00179     increment_refcount();
00180 }
00181 
00182 variant::variant(const variant& v)
00183 {
00184     memcpy(this, &v, sizeof(v));
00185     increment_refcount();
00186 }
00187 
00188 variant::~variant()
00189 {
00190     release();
00191 }
00192 
00193 const variant& variant::operator=(const variant& v)
00194 {
00195     if(&v != this) {
00196         release();
00197         memcpy(this, &v, sizeof(v));
00198         increment_refcount();
00199     }
00200     return *this;
00201 }
00202 
00203 const variant& variant::operator[](size_t n) const
00204 {
00205     if(type_ == TYPE_CALLABLE) {
00206         assert(n == 0);
00207         return *this;
00208     }
00209 
00210     must_be(TYPE_LIST);
00211     assert(list_);
00212     if(n >= list_->elements.size()) {
00213         throw type_error("invalid index");
00214     }
00215 
00216     return list_->elements[n];
00217 }
00218 
00219 const variant& variant::operator[](const variant v) const
00220 {
00221     if(type_ == TYPE_CALLABLE) {
00222         assert(v.as_int() == 0);
00223         return *this;
00224     }
00225 
00226     if(type_ == TYPE_MAP) {
00227         assert(map_);
00228         std::map<variant,variant>::const_iterator i = map_->elements.find(v);
00229         if (i == map_->elements.end())
00230         {
00231             static variant null_variant;
00232             return null_variant;
00233         }
00234         return i->second;
00235     } else if(type_ == TYPE_LIST) {
00236         return operator[](v.as_int());
00237     } else {
00238         throw type_error(formatter() << "type error: " << " expected a list or a map but found " << variant_type_to_string(type_) << " (" << to_debug_string() << ")");
00239     }   
00240 }
00241 
00242 std::map<variant, variant> variant::get_map() const 
00243 {  
00244     must_be(TYPE_MAP); 
00245     return map_->elements; 
00246 }
00247 
00248 variant variant::get_keys() const
00249 {
00250     must_be(TYPE_MAP);
00251     assert(map_);
00252     std::vector<variant> tmp;
00253     for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
00254             tmp.push_back(i->first);
00255     }
00256     return variant(&tmp);
00257 }
00258 
00259 variant variant::get_values() const
00260 {
00261     must_be(TYPE_MAP);
00262     assert(map_);
00263     std::vector<variant> tmp;
00264     for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
00265             tmp.push_back(i->second);
00266     }
00267     return variant(&tmp);
00268 }
00269 
00270 size_t variant::num_elements() const
00271 {
00272     if(type_ == TYPE_CALLABLE) {
00273         return 1;
00274     }
00275 
00276     if (type_ == TYPE_LIST) {
00277         assert(list_);
00278         return list_->elements.size();
00279     } else if (type_ == TYPE_MAP) {
00280         assert(map_);
00281         return map_->elements.size();
00282     } else {
00283         throw type_error(formatter() << "type error: " << " expected a list or a map but found " << variant_type_to_string(type_) << " (" << to_debug_string() << ")");
00284     }
00285 }
00286 
00287 variant variant::get_member(const std::string& str) const
00288 {
00289     if(is_callable()) {
00290         return callable_->query_value(str);
00291     }
00292 
00293     if(str == "self") {
00294         return *this;
00295     } else {
00296         return variant();
00297     }
00298 }
00299 
00300 bool variant::as_bool() const
00301 {
00302     switch(type_) {
00303     case TYPE_NULL:
00304         return false;
00305     case TYPE_INT:
00306         return int_value_ != 0;
00307     case TYPE_CALLABLE:
00308         return callable_ != NULL;
00309     case TYPE_LIST:
00310         return !list_->elements.empty();
00311     case TYPE_MAP:
00312         return !map_->elements.empty();
00313     case TYPE_STRING:
00314         return !string_->str.empty();
00315     default:
00316         assert(false);
00317         return false;
00318     }
00319 }
00320 
00321 const std::string& variant::as_string() const
00322 {
00323     must_be(TYPE_STRING);
00324     assert(string_);
00325     return string_->str;
00326 }
00327 
00328 variant variant::operator+(const variant& v) const
00329 {
00330     if(type_ == TYPE_LIST) {
00331         if(v.type_ == TYPE_LIST) {
00332             std::vector<variant> res;
00333             res.reserve(list_->elements.size() + v.list_->elements.size());
00334             for(size_t i = 0; i<list_->elements.size(); ++i) {
00335                 const variant& var = list_->elements[i];
00336                 res.push_back(var);
00337             }
00338 
00339             for(size_t j = 0; j<v.list_->elements.size(); ++j) {
00340                 const variant& var = v.list_->elements[j];
00341                 res.push_back(var);
00342             }
00343 
00344             return variant(&res);
00345         }
00346     }
00347     if(type_ == TYPE_MAP) {
00348         if(v.type_ == TYPE_MAP) {
00349             std::map<variant,variant> res(map_->elements);
00350 
00351             for(std::map<variant,variant>::const_iterator i = v.map_->elements.begin(); i != v.map_->elements.end(); ++i) {
00352                 res[i->first] = i->second;
00353             }
00354 
00355             return variant(&res);
00356         }
00357     }
00358 
00359     return variant(as_int() + v.as_int());
00360 }
00361 
00362 variant variant::operator-(const variant& v) const
00363 {
00364     return variant(as_int() - v.as_int());
00365 }
00366 
00367 variant variant::operator*(const variant& v) const
00368 {
00369     return variant(as_int() * v.as_int());
00370 }
00371 
00372 variant variant::operator/(const variant& v) const
00373 {
00374     const int numerator = as_int();
00375     const int denominator = v.as_int();
00376     if(denominator == 0) {
00377         throw type_error(formatter() << "divide by zero error");
00378     }
00379 
00380     return variant(numerator/denominator);
00381 }
00382 
00383 variant variant::operator%(const variant& v) const
00384 {
00385     const int numerator = as_int();
00386     const int denominator = v.as_int();
00387     if(denominator == 0) {
00388         throw type_error(formatter() << "divide by zero error");
00389     }
00390 
00391     return variant(numerator%denominator);
00392 }
00393 
00394 variant variant::operator^(const variant& v) const
00395 {
00396     return variant(static_cast<int>(pow(as_int(), v.as_int())));
00397 }
00398 
00399 variant variant::operator-() const
00400 {
00401     return variant(-as_int());
00402 }
00403 
00404 bool variant::operator==(const variant& v) const
00405 {
00406     if(type_ != v.type_) {
00407         return false;
00408     }
00409 
00410     switch(type_) {
00411     case TYPE_NULL: {
00412         return v.is_null();
00413     }
00414 
00415     case TYPE_STRING: {
00416         return string_->str == v.string_->str;
00417     }
00418 
00419     case TYPE_INT: {
00420         return int_value_ == v.int_value_;
00421     }
00422 
00423     case TYPE_LIST: {
00424         if(num_elements() != v.num_elements()) {
00425             return false;
00426         }
00427 
00428         for(size_t n = 0; n != num_elements(); ++n) {
00429             if((*this)[n] != v[n]) {
00430                 return false;
00431             }
00432         }
00433 
00434         return true;
00435     }
00436 
00437     case TYPE_MAP: {
00438         return map_->elements == v.map_->elements;
00439     }
00440 
00441     case TYPE_CALLABLE: {
00442         return callable_->equals(v.callable_);
00443     }
00444     }
00445 
00446     assert(false);
00447     return false;
00448 }
00449 
00450 bool variant::operator!=(const variant& v) const
00451 {
00452     return !operator==(v);
00453 }
00454 
00455 bool variant::operator<=(const variant& v) const
00456 {
00457     if(type_ != v.type_) {
00458         return type_ < v.type_;
00459     }
00460 
00461     switch(type_) {
00462     case TYPE_NULL: {
00463         return true;
00464     }
00465 
00466     case TYPE_STRING: {
00467         return string_->str <= v.string_->str;
00468     }
00469 
00470     case TYPE_INT: {
00471         return int_value_ <= v.int_value_;
00472     }
00473 
00474     case TYPE_LIST: {
00475         for(size_t n = 0; n != num_elements() && n != v.num_elements(); ++n) {
00476             if((*this)[n] < v[n]) {
00477                 return true;
00478             } else if((*this)[n] > v[n]) {
00479                 return false;
00480             }
00481         }
00482 
00483         return num_elements() <= v.num_elements();
00484     }
00485 
00486     case TYPE_MAP: {
00487         return map_->elements <= v.map_->elements;
00488     }
00489 
00490     case TYPE_CALLABLE: {
00491         return !v.callable_->less(callable_);
00492     }
00493     }
00494 
00495     assert(false);
00496     return false;
00497 }
00498 
00499 bool variant::operator>=(const variant& v) const
00500 {
00501     return v <= *this;
00502 }
00503 
00504 bool variant::operator<(const variant& v) const
00505 {
00506     return !(*this >= v);
00507 }
00508 
00509 bool variant::operator>(const variant& v) const
00510 {
00511     return !(*this <= v);
00512 }
00513 
00514 void variant::must_be(variant::TYPE t) const
00515 {
00516     if(type_ != t) {
00517         throw type_error(formatter() << "type error: " << " expected " << variant_type_to_string(t) << " but found " << variant_type_to_string(type_) << " (" << to_debug_string() << ")");
00518     }
00519 }
00520 
00521 void variant::serialize_to_string(std::string& str) const
00522 {
00523     switch(type_) {
00524     case TYPE_NULL:
00525         str += "null()";
00526     case TYPE_INT:
00527         str += boost::lexical_cast<std::string>(int_value_);
00528         break;
00529     case TYPE_CALLABLE:
00530         callable_->serialize(str);
00531         break;
00532     case TYPE_LIST: {
00533         str += "[";
00534         bool first_time = true;
00535         for(size_t i=0; i<list_->elements.size(); ++i) {
00536             const variant& var = list_->elements[i];
00537             if(!first_time) {
00538                 str += ",";
00539             }
00540             first_time = false;
00541             var.serialize_to_string(str);
00542         }
00543         str += "]";
00544         break;
00545     }
00546     case TYPE_MAP: {
00547         str += "{";
00548         bool first_time = true;
00549         for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
00550             if(!first_time) {
00551                 str += ",";
00552             }
00553             first_time = false;
00554             i->first.serialize_to_string(str);
00555             str += "->";
00556             i->second.serialize_to_string(str);
00557         }
00558         str += "}";
00559         break;
00560     }
00561     case TYPE_STRING:
00562         str += "'";
00563         str += string_->str;
00564         str += "'";
00565         break;
00566     default:
00567         assert(false);
00568     }
00569 }
00570 
00571 void variant::serialize_from_string(const std::string& str)
00572 {
00573     try {
00574         *this = game_logic::formula(str).execute();
00575     } catch(...) {
00576         *this = variant(str);
00577     }
00578 }
00579 
00580 int variant::refcount() const
00581 {
00582     switch(type_) {
00583     case TYPE_LIST:
00584         return list_->refcount;
00585         break;
00586     case TYPE_STRING:
00587         return string_->refcount;
00588         break;
00589     case TYPE_MAP:
00590         return map_->refcount;
00591         break;
00592     case TYPE_CALLABLE:
00593         return callable_->refcount();
00594         break;
00595     default:
00596         return -1;
00597     }
00598 }
00599 
00600 std::string variant::string_cast() const
00601 {
00602     switch(type_) {
00603     case TYPE_NULL:
00604         return "0";
00605     case TYPE_INT:
00606         return boost::lexical_cast<std::string>(int_value_);
00607     case TYPE_CALLABLE:
00608         return "(object)";
00609     case TYPE_LIST: {
00610         std::string res = "";
00611         for(size_t i=0; i<list_->elements.size(); ++i) {
00612             const variant& var = list_->elements[i];
00613             if(!res.empty()) {
00614                 res += ", ";
00615             }
00616 
00617             res += var.string_cast();
00618         }
00619 
00620         return res;
00621     }
00622     case TYPE_MAP: {
00623         std::string res = "";
00624         for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
00625             if(!res.empty()) {
00626                 res += ",";
00627             }
00628             res += i->first.string_cast();
00629             res += "->";
00630             res += i->second.string_cast();
00631         }
00632         return res;
00633     }
00634 
00635     case TYPE_STRING:
00636         return string_->str;
00637     default:
00638         assert(false);
00639         return "invalid";
00640     }
00641 }
00642 
00643 std::string variant::to_debug_string(std::vector<const game_logic::formula_callable*>* seen) const
00644 {
00645     std::vector<const game_logic::formula_callable*> seen_stack;
00646     if(!seen) {
00647         seen = &seen_stack;
00648     }
00649 
00650     std::ostringstream s;
00651     switch(type_) {
00652     case TYPE_NULL:
00653         s << "(null)";
00654     case TYPE_INT:
00655         s << int_value_;
00656         break;
00657     case TYPE_LIST: {
00658         s << "[";
00659         for(size_t n = 0; n != num_elements(); ++n) {
00660             if(n != 0) {
00661                 s << ", ";
00662             }
00663 
00664             s << operator[](n).to_debug_string(seen);
00665         }
00666         s << "]";
00667         break;
00668     }
00669     case TYPE_CALLABLE: {
00670         s << "{";
00671         if(std::find(seen->begin(), seen->end(), callable_) == seen->end()) {
00672             seen->push_back(callable_);
00673             std::vector<game_logic::formula_input> v = callable_->inputs();
00674             bool first = true;
00675             for(size_t i=0; i<v.size(); ++i) {
00676                 const game_logic::formula_input& input = v[i];
00677                 if(!first) {
00678                     s << ", ";
00679                 }
00680                 first = false;
00681                 s << input.name << " ";
00682                 if(input.access == game_logic::FORMULA_READ_WRITE) {
00683                     s << "(read-write) ";
00684                 } else if(input.access == game_logic::FORMULA_WRITE_ONLY) {
00685                     s << "(writeonly) ";
00686                 }
00687 
00688                 s << "-> " << callable_->query_value(input.name).to_debug_string(seen);
00689             }
00690         } else {
00691             s << "...";
00692         }
00693         s << "}";
00694         break;
00695     }
00696     case TYPE_MAP: {
00697         s << "{";
00698         bool first_time = true;
00699         for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
00700             if(!first_time) {
00701                 s << ",";
00702             }
00703             first_time = false;
00704             s << i->first.to_debug_string(seen);
00705             s << "->";
00706             s << i->second.to_debug_string(seen);
00707         }
00708         s << "}";
00709         break;
00710     }
00711     case TYPE_STRING: {
00712         s << "'" << string_->str << "'";
00713         break;
00714     }
00715     }
00716 
00717     return s.str();
00718 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs