variant.cpp

Go to the documentation of this file.
00001 /* $Id: variant.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2008 - 2012 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #include "global.hpp"
00017 
00018 #include <cmath>
00019 #include <iostream>
00020 #include <string.h>
00021 
00022 #include "boost/lexical_cast.hpp"
00023 
00024 #include "formatter.hpp"
00025 #include "formula_callable.hpp"
00026 #include "formula_function.hpp"
00027 #include "util.hpp"
00028 
00029 namespace {
00030 std::string variant_type_to_string(variant::TYPE type) {
00031     switch(type) {
00032     case variant::TYPE_NULL:
00033         return "null";
00034     case variant::TYPE_INT:
00035         return "int";
00036     case variant::TYPE_DECIMAL:
00037         return "decimal";
00038     case variant::TYPE_CALLABLE:
00039         return "object";
00040     case variant::TYPE_LIST:
00041         return "list";
00042     case variant::TYPE_STRING:
00043         return "string";
00044     case variant::TYPE_MAP:
00045         return "map";
00046     default:
00047         assert(false);
00048         return "invalid";
00049     }
00050 }
00051 
00052 std::vector<const char*> call_stack;
00053 }
00054 
00055 void push_call_stack(const char* str)
00056 {
00057     call_stack.push_back(str);
00058 }
00059 
00060 void pop_call_stack()
00061 {
00062     call_stack.pop_back();
00063 }
00064 
00065 std::string get_call_stack()
00066 {
00067     std::string res;
00068     for(std::vector<const char*>::const_iterator i = call_stack.begin();
00069         i != call_stack.end(); ++i) {
00070         if(!*i) {
00071             continue;
00072         }
00073         res += "  ";
00074         res += *i;
00075         res += "\n";
00076     }
00077     return res;
00078 }
00079 
00080 type_error::type_error(const std::string& str) : game::error(str) {
00081     std::cerr << "ERROR: " << message << "\n" << get_call_stack();
00082 }
00083 
00084 variant_iterator::variant_iterator()
00085     : type_(TYPE_NULL)
00086     , list_iterator_()
00087     , map_iterator_()
00088 {
00089 }
00090 
00091 variant_iterator::variant_iterator(const variant_iterator& iter)
00092     : type_(iter.type_)
00093     , list_iterator_()
00094     , map_iterator_()
00095 {
00096     switch(type_) {
00097         case TYPE_LIST :
00098             list_iterator_ = iter.list_iterator_;
00099             break;
00100 
00101         case TYPE_MAP:
00102             map_iterator_ = iter.map_iterator_;
00103             break;
00104 
00105         case TYPE_NULL:
00106             /* DO NOTHING */
00107             break;
00108     }
00109 }
00110 
00111 variant_iterator::variant_iterator(
00112         const std::vector<variant>::iterator& iter)
00113     : type_(TYPE_LIST)
00114     , list_iterator_(iter)
00115     , map_iterator_()
00116 {
00117 }
00118 
00119 variant_iterator::variant_iterator(
00120         const std::map<variant, variant>::iterator& iter)
00121     : type_(TYPE_MAP)
00122     , list_iterator_()
00123     , map_iterator_(iter)
00124 {
00125 }
00126 
00127 variant variant_iterator::operator*() const
00128 {
00129     if (type_ == TYPE_LIST)
00130     {
00131         return variant( *list_iterator_);
00132     } else if (type_ == TYPE_MAP)
00133     {
00134         game_logic::key_value_pair* p = new game_logic::key_value_pair( map_iterator_->first, map_iterator_->second );
00135         variant  res( p );
00136         return res;
00137     } else
00138         return variant();
00139 }
00140 
00141 variant_iterator& variant_iterator::operator++()
00142 {
00143     if (type_ == TYPE_LIST)
00144     {
00145         ++list_iterator_;
00146     } else if (type_ == TYPE_MAP)
00147     {
00148         ++map_iterator_;
00149     }
00150 
00151     return *this;
00152 }
00153 
00154 variant_iterator variant_iterator::operator++(int)
00155 {
00156     variant_iterator iter(*this);
00157     if (type_ == TYPE_LIST)
00158     {
00159         ++list_iterator_;
00160     } else if (type_ == TYPE_MAP)
00161     {
00162         ++map_iterator_;
00163     }
00164 
00165     return iter;
00166 }
00167 
00168 variant_iterator& variant_iterator::operator=(const variant_iterator& that)
00169 {
00170     if (this == &that)
00171         return *this;
00172     type_ = that.type_;
00173     switch(type_) {
00174         case TYPE_LIST :
00175             list_iterator_ = that.list_iterator_;
00176             break;
00177 
00178         case TYPE_MAP:
00179             map_iterator_ = that.map_iterator_;
00180             break;
00181 
00182         case TYPE_NULL:
00183             /* DO NOTHING */
00184             break;
00185     }
00186 
00187     return *this;
00188 }
00189 
00190 bool variant_iterator::operator==(const variant_iterator& that) const
00191 {
00192     if (type_ == TYPE_LIST)
00193     {
00194         if (that.type_ != TYPE_LIST)
00195             return false;
00196         return list_iterator_ == that.list_iterator_;
00197     } else if (type_ == TYPE_MAP)
00198     {
00199         if (that.type_ != TYPE_MAP)
00200             return false;
00201         return map_iterator_ == that.map_iterator_;
00202     } else if (type_ == TYPE_NULL &&  that.type_ == TYPE_NULL )
00203         return true;
00204     else
00205         return false;
00206 }
00207 
00208 bool variant_iterator::operator!=(const variant_iterator& that) const
00209 {
00210     if (type_ == TYPE_LIST)
00211     {
00212         if (that.type_ != TYPE_LIST)
00213             return true;
00214         return list_iterator_ != that.list_iterator_;
00215     } else if (type_ == TYPE_MAP)
00216     {
00217         if (that.type_ != TYPE_MAP)
00218             return true;
00219         return map_iterator_ != that.map_iterator_;
00220     } else if (type_ == TYPE_NULL &&  that.type_ == TYPE_NULL )
00221         return false;
00222     else
00223         return true;
00224 }
00225 
00226 struct variant_list {
00227     variant_list()
00228         : elements()
00229         , refcount(0)
00230     {
00231     }
00232 
00233     std::vector<variant> elements;
00234     int refcount;
00235 };
00236 
00237 struct variant_string {
00238     variant_string()
00239         : str()
00240         , refcount(0)
00241     {
00242     }
00243 
00244     std::string str;
00245     int refcount;
00246 };
00247 
00248 struct variant_map {
00249     variant_map()
00250         : elements()
00251         , refcount(0)
00252     {
00253     }
00254 
00255     std::map<variant,variant> elements;
00256     int refcount;
00257 };
00258 
00259 void variant::increment_refcount()
00260 {
00261     switch(type_) {
00262     case TYPE_LIST:
00263         ++list_->refcount;
00264         break;
00265     case TYPE_STRING:
00266         ++string_->refcount;
00267         break;
00268     case TYPE_MAP:
00269         ++map_->refcount;
00270         break;
00271     case TYPE_CALLABLE:
00272         intrusive_ptr_add_ref(callable_);
00273         break;
00274 
00275     // These are not used here, add them to silence a compiler warning.
00276     case TYPE_NULL:
00277     case TYPE_DECIMAL:
00278     case TYPE_INT :
00279         break;
00280     }
00281 }
00282 
00283 void variant::release()
00284 {
00285     switch(type_) {
00286     case TYPE_LIST:
00287         if(--list_->refcount == 0) {
00288             delete list_;
00289         }
00290         break;
00291     case TYPE_STRING:
00292         if(--string_->refcount == 0) {
00293             delete string_;
00294         }
00295         break;
00296     case TYPE_MAP:
00297         if(--map_->refcount == 0) {
00298             delete map_;
00299         }
00300         break;
00301     case TYPE_CALLABLE:
00302         intrusive_ptr_release(callable_);
00303         break;
00304 
00305     // These are not used here, add them to silence a compiler warning.
00306     case TYPE_NULL:
00307     case TYPE_DECIMAL:
00308     case TYPE_INT :
00309         break;
00310     }
00311 }
00312 
00313 variant::variant() : type_(TYPE_NULL), int_value_(0)
00314 {}
00315 
00316 variant::variant(int n) : type_(TYPE_INT), int_value_(n)
00317 {}
00318 
00319 variant::variant(int n, variant::DECIMAL_VARIANT_TYPE /*type*/) : type_(TYPE_DECIMAL), decimal_value_(n)
00320 {}
00321 
00322 variant::variant(const game_logic::formula_callable* callable)
00323     : type_(TYPE_CALLABLE), callable_(callable)
00324 {
00325     assert(callable_);
00326     increment_refcount();
00327 }
00328 
00329 variant::variant(std::vector<variant>* array)
00330     : type_(TYPE_LIST)
00331 {
00332     assert(array);
00333     list_ = new variant_list;
00334     list_->elements.swap(*array);
00335     increment_refcount();
00336 }
00337 
00338 variant::variant(const std::string& str)
00339     : type_(TYPE_STRING)
00340 {
00341     string_ = new variant_string;
00342     string_->str = str;
00343     increment_refcount();
00344 }
00345 
00346 variant::variant(std::map<variant,variant>* map)
00347     : type_(TYPE_MAP)
00348 {
00349     assert(map);
00350     map_ = new variant_map;
00351     map_->elements.swap(*map);
00352     increment_refcount();
00353 }
00354 
00355 variant::variant(const variant& v)
00356     : type_(v.type_)
00357 {
00358     memcpy(this, &v, sizeof(v));
00359     increment_refcount();
00360 }
00361 
00362 variant::~variant()
00363 {
00364     release();
00365 }
00366 
00367 const variant& variant::operator=(const variant& v)
00368 {
00369     if(&v != this) {
00370         release();
00371         memcpy(this, &v, sizeof(v));
00372         increment_refcount();
00373     }
00374     return *this;
00375 }
00376 
00377 const variant& variant::operator[](size_t n) const
00378 {
00379     if(type_ == TYPE_CALLABLE) {
00380         assert(n == 0);
00381         return *this;
00382     }
00383 
00384     must_be(TYPE_LIST);
00385     assert(list_);
00386     if(n >= list_->elements.size()) {
00387         throw type_error("invalid index");
00388     }
00389 
00390     return list_->elements[n];
00391 }
00392 
00393 const variant& variant::operator[](const variant& v) const
00394 {
00395     if(type_ == TYPE_CALLABLE) {
00396         assert(v.as_int() == 0);
00397         return *this;
00398     }
00399 
00400     if(type_ == TYPE_MAP) {
00401         assert(map_);
00402         std::map<variant,variant>::const_iterator i = map_->elements.find(v);
00403         if (i == map_->elements.end())
00404         {
00405             static variant null_variant;
00406             return null_variant;
00407         }
00408         return i->second;
00409     } else if(type_ == TYPE_LIST) {
00410         return operator[](v.as_int());
00411     } else {
00412         throw type_error((formatter() << "type error: "
00413             << " expected a list or a map but found "
00414             << variant_type_to_string(type_)
00415             << " (" << to_debug_string() << ")").str());
00416     }
00417 }
00418 
00419 variant variant::get_keys() const
00420 {
00421     must_be(TYPE_MAP);
00422     assert(map_);
00423     std::vector<variant> tmp;
00424     for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
00425             tmp.push_back(i->first);
00426     }
00427     return variant(&tmp);
00428 }
00429 
00430 variant variant::get_values() const
00431 {
00432     must_be(TYPE_MAP);
00433     assert(map_);
00434     std::vector<variant> tmp;
00435     for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
00436             tmp.push_back(i->second);
00437     }
00438     return variant(&tmp);
00439 }
00440 
00441 variant_iterator variant::begin() const
00442 {
00443     if(type_ == TYPE_LIST)
00444         return variant_iterator( list_->elements.begin() );
00445 
00446     if(type_ == TYPE_MAP)
00447         return variant_iterator( map_->elements.begin() );
00448 
00449     return variant_iterator();
00450 }
00451 variant_iterator variant::end() const
00452 {
00453     if(type_ == TYPE_LIST)
00454         return variant_iterator( list_->elements.end() );
00455 
00456     if(type_ == TYPE_MAP)
00457         return variant_iterator( map_->elements.end() );
00458 
00459     return variant_iterator();
00460 }
00461 
00462 bool variant::is_empty() const
00463 {
00464     if(type_ == TYPE_NULL) {
00465         return true;
00466     } else if (type_ == TYPE_LIST) {
00467         assert(list_);
00468         return list_->elements.empty();
00469     } else if (type_ == TYPE_MAP) {
00470         assert(map_);
00471         return map_->elements.empty();
00472     }
00473 
00474     return false;
00475 }
00476 
00477 size_t variant::num_elements() const
00478 {
00479     if(type_ == TYPE_CALLABLE) {
00480         return 1;
00481     }
00482 
00483     if (type_ == TYPE_LIST) {
00484         assert(list_);
00485         return list_->elements.size();
00486     } else if (type_ == TYPE_MAP) {
00487         assert(map_);
00488         return map_->elements.size();
00489     } else {
00490         throw type_error((formatter() << "type error: "
00491             << " expected a list or a map but found "
00492             << variant_type_to_string(type_)
00493             << " (" << to_debug_string() << ")").str());
00494     }
00495 }
00496 
00497 variant variant::get_member(const std::string& str) const
00498 {
00499     if(is_callable()) {
00500         return callable_->query_value(str);
00501     }
00502 
00503     if(str == "self") {
00504         return *this;
00505     } else {
00506         return variant();
00507     }
00508 }
00509 
00510 int variant::as_decimal() const
00511 {
00512     if( type_ == TYPE_DECIMAL) {
00513         return decimal_value_;
00514     } else if( type_ == TYPE_INT ) {
00515         return int_value_*1000;
00516     } else if( type_ == TYPE_NULL) {
00517         return 0;
00518     } else {
00519         throw type_error((formatter() << "type error: "
00520             << " expected integer or decimal but found "
00521             << variant_type_to_string(type_)
00522             << " (" << to_debug_string() << ")").str());
00523     }
00524 }
00525 
00526 bool variant::as_bool() const
00527 {
00528     switch(type_) {
00529     case TYPE_NULL:
00530         return false;
00531     case TYPE_INT:
00532         return int_value_ != 0;
00533     case TYPE_DECIMAL:
00534         return decimal_value_ != 0;
00535     case TYPE_CALLABLE:
00536         return callable_ != NULL;
00537     case TYPE_LIST:
00538         return !list_->elements.empty();
00539     case TYPE_MAP:
00540         return !map_->elements.empty();
00541     case TYPE_STRING:
00542         return !string_->str.empty();
00543     default:
00544         assert(false);
00545         return false;
00546     }
00547 }
00548 
00549 const std::string& variant::as_string() const
00550 {
00551     must_be(TYPE_STRING);
00552     assert(string_);
00553     return string_->str;
00554 }
00555 
00556 variant variant::operator+(const variant& v) const
00557 {
00558     if(type_ == TYPE_LIST) {
00559         if(v.type_ == TYPE_LIST) {
00560             std::vector<variant> res;
00561             res.reserve(list_->elements.size() + v.list_->elements.size());
00562             for(size_t i = 0; i<list_->elements.size(); ++i) {
00563                 const variant& var = list_->elements[i];
00564                 res.push_back(var);
00565             }
00566 
00567             for(size_t j = 0; j<v.list_->elements.size(); ++j) {
00568                 const variant& var = v.list_->elements[j];
00569                 res.push_back(var);
00570             }
00571 
00572             return variant(&res);
00573         }
00574     }
00575     if(type_ == TYPE_MAP) {
00576         if(v.type_ == TYPE_MAP) {
00577             std::map<variant,variant> res(map_->elements);
00578 
00579             for(std::map<variant,variant>::const_iterator i = v.map_->elements.begin(); i != v.map_->elements.end(); ++i) {
00580                 res[i->first] = i->second;
00581             }
00582 
00583             return variant(&res);
00584         }
00585     }
00586     if(type_ == TYPE_DECIMAL || v.type_ == TYPE_DECIMAL) {
00587         return variant( as_decimal() + v.as_decimal() , DECIMAL_VARIANT);
00588     }
00589 
00590     return variant(as_int() + v.as_int());
00591 }
00592 
00593 variant variant::operator-(const variant& v) const
00594 {
00595     if(type_ == TYPE_DECIMAL || v.type_ == TYPE_DECIMAL) {
00596         return variant( as_decimal() - v.as_decimal() , DECIMAL_VARIANT);
00597     }
00598 
00599     return variant(as_int() - v.as_int());
00600 }
00601 
00602 variant variant::operator*(const variant& v) const
00603 {
00604     if(type_ == TYPE_DECIMAL || v.type_ == TYPE_DECIMAL) {
00605 
00606         long long long_int = as_decimal();
00607 
00608         long_int *= v.as_decimal();
00609 
00610         long_int /= 100;
00611 
00612         if( long_int%10 >= 5) {
00613             long_int /= 10;
00614             ++long_int;
00615         } else
00616             long_int/=10;
00617 
00618         return variant( static_cast<int>(long_int) , variant::DECIMAL_VARIANT );
00619     }
00620 
00621     return variant(as_int() * v.as_int());
00622 }
00623 
00624 variant variant::operator/(const variant& v) const
00625 {
00626     if(type_ == TYPE_DECIMAL || v.type_ == TYPE_DECIMAL) {
00627         int denominator = v.as_decimal();
00628 
00629         if(denominator == 0) {
00630             throw type_error((formatter() << "divide by zero error").str());
00631         }
00632 
00633         long long long_int = as_decimal();
00634 
00635         long_int *= 10000;
00636 
00637         long_int /= denominator;
00638 
00639         if( long_int%10 >= 5) {
00640             long_int /= 10;
00641             ++long_int;
00642         } else
00643             long_int/=10;
00644 
00645         return variant(  static_cast<int>(long_int) , variant::DECIMAL_VARIANT);
00646     }
00647 
00648 
00649     const int numerator = as_int();
00650     const int denominator = v.as_int();
00651     if(denominator == 0) {
00652         throw type_error((formatter() << "divide by zero error").str());;
00653     }
00654 
00655     return variant(numerator/denominator);
00656 }
00657 
00658 variant variant::operator%(const variant& v) const
00659 {
00660     const int numerator = as_int();
00661     const int denominator = v.as_int();
00662     if(denominator == 0) {
00663         throw type_error((formatter() << "divide by zero error").str());
00664     }
00665 
00666     return variant(numerator%denominator);
00667 }
00668 
00669 
00670 variant variant::operator^(const variant& v) const
00671 {
00672     if( type_ == TYPE_DECIMAL || v.type_ == TYPE_DECIMAL ) {
00673 
00674         double res = pow( as_decimal()/1000.0 , v.as_decimal()/1000.0 );
00675 
00676         res *= 1000;
00677         int i =  static_cast<int>( res );
00678 
00679         res -= i;
00680 
00681         if( res > 0.5 )
00682             i++;
00683 
00684         return variant( i , variant::DECIMAL_VARIANT);
00685     }
00686 
00687     return variant(static_cast<int>(
00688             round_portable(pow(static_cast<double>(as_int()), v.as_int()))));
00689 }
00690 
00691 variant variant::operator-() const
00692 {
00693     if( type_ == TYPE_DECIMAL)
00694         return variant( -decimal_value_, variant::DECIMAL_VARIANT );
00695 
00696     return variant(-as_int());
00697 }
00698 
00699 bool variant::operator==(const variant& v) const
00700 {
00701     if(type_ != v.type_) {
00702         if( type_ == TYPE_DECIMAL || v.type_ == TYPE_DECIMAL ) {
00703             return as_decimal() == v.as_decimal();
00704         }
00705 
00706         return false;
00707     }
00708 
00709     switch(type_) {
00710     case TYPE_NULL: {
00711         return v.is_null();
00712     }
00713 
00714     case TYPE_STRING: {
00715         return string_->str == v.string_->str;
00716     }
00717 
00718     case TYPE_INT: {
00719         return int_value_ == v.int_value_;
00720     }
00721 
00722     case TYPE_DECIMAL: {
00723         return decimal_value_ == v.decimal_value_;
00724     }
00725 
00726     case TYPE_LIST: {
00727         if(num_elements() != v.num_elements()) {
00728             return false;
00729         }
00730 
00731         for(size_t n = 0; n != num_elements(); ++n) {
00732             if((*this)[n] != v[n]) {
00733                 return false;
00734             }
00735         }
00736 
00737         return true;
00738     }
00739 
00740     case TYPE_MAP: {
00741         return map_->elements == v.map_->elements;
00742     }
00743 
00744     case TYPE_CALLABLE: {
00745         return callable_->equals(v.callable_);
00746     }
00747     }
00748 
00749     assert(false);
00750     return false;
00751 }
00752 
00753 bool variant::operator!=(const variant& v) const
00754 {
00755     return !operator==(v);
00756 }
00757 
00758 bool variant::operator<=(const variant& v) const
00759 {
00760     if(type_ != v.type_) {
00761         if( type_ == TYPE_DECIMAL || v.type_ == TYPE_DECIMAL ) {
00762             return as_decimal() <= v.as_decimal();
00763         }
00764 
00765         return type_ < v.type_;
00766     }
00767 
00768     switch(type_) {
00769     case TYPE_NULL: {
00770         return true;
00771     }
00772 
00773     case TYPE_STRING: {
00774         return string_->str <= v.string_->str;
00775     }
00776 
00777     case TYPE_INT: {
00778         return int_value_ <= v.int_value_;
00779     }
00780 
00781     case TYPE_DECIMAL: {
00782         return decimal_value_ <= v.decimal_value_;
00783     }
00784 
00785     case TYPE_LIST: {
00786         for(size_t n = 0; n != num_elements() && n != v.num_elements(); ++n) {
00787             if((*this)[n] < v[n]) {
00788                 return true;
00789             } else if((*this)[n] > v[n]) {
00790                 return false;
00791             }
00792         }
00793 
00794         return num_elements() <= v.num_elements();
00795     }
00796 
00797     case TYPE_MAP: {
00798         return map_->elements <= v.map_->elements;
00799     }
00800 
00801     case TYPE_CALLABLE: {
00802         return !v.callable_->less(callable_);
00803     }
00804     }
00805 
00806     assert(false);
00807     return false;
00808 }
00809 
00810 bool variant::operator>=(const variant& v) const
00811 {
00812     return v <= *this;
00813 }
00814 
00815 bool variant::operator<(const variant& v) const
00816 {
00817     return !(*this >= v);
00818 }
00819 
00820 bool variant::operator>(const variant& v) const
00821 {
00822     return !(*this <= v);
00823 }
00824 
00825 variant variant::list_elements_add(const variant& v) const
00826 {
00827     must_be(TYPE_LIST);
00828     v.must_be(TYPE_LIST);
00829 
00830     if( num_elements() != v.num_elements() )
00831         throw type_error("Operator '.+' requires two lists of the same length");
00832 
00833     std::vector< variant > res;
00834     res.reserve(num_elements());
00835 
00836     for(size_t i = 0; i < num_elements(); ++i) {
00837         res.push_back( (*this)[i] + v[i] );
00838     }
00839 
00840     return variant( &res );
00841 }
00842 
00843 variant variant::list_elements_sub(const variant& v) const
00844 {
00845     must_be(TYPE_LIST);
00846     v.must_be(TYPE_LIST);
00847 
00848     if( num_elements() != v.num_elements() )
00849         throw type_error("Operator '.-' requires two lists of the same length");
00850 
00851     std::vector< variant > res;
00852     res.reserve(num_elements());
00853 
00854     for(size_t i = 0; i < num_elements(); ++i) {
00855         res.push_back( (*this)[i] - v[i] );
00856     }
00857 
00858     return variant( &res );
00859 }
00860 
00861 variant variant::list_elements_mul(const variant& v) const
00862 {
00863     must_be(TYPE_LIST);
00864     v.must_be(TYPE_LIST);
00865 
00866     if( num_elements() != v.num_elements() )
00867         throw type_error("Operator '.*' requires two lists of the same length");
00868 
00869     std::vector< variant > res;
00870     res.reserve(num_elements());
00871 
00872     for(size_t i = 0; i < num_elements(); ++i) {
00873         res.push_back( (*this)[i] * v[i] );
00874     }
00875 
00876     return variant( &res );
00877 }
00878 
00879 variant variant::list_elements_div(const variant& v) const
00880 {
00881     must_be(TYPE_LIST);
00882     v.must_be(TYPE_LIST);
00883 
00884     if( num_elements() != v.num_elements() )
00885         throw type_error("Operator './' requires two lists of the same length");
00886 
00887     std::vector< variant > res;
00888     res.reserve(num_elements());
00889 
00890     for(size_t i = 0; i < num_elements(); ++i) {
00891         res.push_back( (*this)[i] / v[i] );
00892     }
00893 
00894     return variant( &res );
00895 }
00896 
00897 void variant::must_be(variant::TYPE t) const
00898 {
00899     if(type_ != t) {
00900         throw type_error((formatter() << "type error: " << " expected "
00901             << variant_type_to_string(t) << " but found "
00902             << variant_type_to_string(type_)
00903             << " (" << to_debug_string() << ")").str());
00904     }
00905 }
00906 
00907 void variant::serialize_to_string(std::string& str) const
00908 {
00909     switch(type_) {
00910     case TYPE_NULL:
00911         str += "null()";
00912     case TYPE_INT:
00913         str += boost::lexical_cast<std::string>(int_value_);
00914         break;
00915     case TYPE_DECIMAL: {
00916         std::ostringstream s;
00917 
00918         int fractional = decimal_value_ % 1000;
00919         int integer = (decimal_value_ - fractional) / 1000;
00920 
00921         s << integer << ".";
00922 
00923         fractional = abs(fractional);
00924 
00925         if( fractional < 100) {
00926             if( fractional < 10)
00927                 s << "00";
00928             else
00929                 s << 0;
00930         }
00931 
00932         s << fractional;
00933 
00934         str += s.str();
00935         break;
00936     }
00937     case TYPE_CALLABLE:
00938         callable_->serialize(str);
00939         break;
00940     case TYPE_LIST: {
00941         str += "[";
00942         bool first_time = true;
00943         for(size_t i=0; i<list_->elements.size(); ++i) {
00944             const variant& var = list_->elements[i];
00945             if(!first_time) {
00946                 str += ",";
00947             }
00948             first_time = false;
00949             var.serialize_to_string(str);
00950         }
00951         str += "]";
00952         break;
00953     }
00954     case TYPE_MAP: {
00955         str += "[";
00956         bool first_time = true;
00957         for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
00958             if(!first_time) {
00959                 str += ",";
00960             }
00961             first_time = false;
00962             i->first.serialize_to_string(str);
00963             str += "->";
00964             i->second.serialize_to_string(str);
00965         }
00966         str += "]";
00967         break;
00968     }
00969     case TYPE_STRING:
00970         str += "'";
00971         str += string_->str;
00972         str += "'";
00973         break;
00974     default:
00975         assert(false);
00976     }
00977 }
00978 
00979 void variant::serialize_from_string(const std::string& str)
00980 {
00981     try {
00982         *this = game_logic::formula(str).evaluate();
00983     } catch(...) {
00984         *this = variant(str);
00985     }
00986 }
00987 
00988 int variant::refcount() const
00989 {
00990     switch(type_) {
00991     case TYPE_LIST:
00992         return list_->refcount;
00993         break;
00994     case TYPE_STRING:
00995         return string_->refcount;
00996         break;
00997     case TYPE_MAP:
00998         return map_->refcount;
00999         break;
01000     case TYPE_CALLABLE:
01001         return callable_->refcount();
01002         break;
01003     default:
01004         return -1;
01005     }
01006 }
01007 
01008 std::string variant::string_cast() const
01009 {
01010     switch(type_) {
01011     case TYPE_NULL:
01012         return "0";
01013     case TYPE_INT:
01014         return boost::lexical_cast<std::string>(int_value_);
01015     case TYPE_DECIMAL: {
01016         std::ostringstream s;
01017 
01018         int fractional = decimal_value_ % 1000;
01019         int integer = (decimal_value_ - fractional) / 1000;
01020 
01021         s << integer << ".";
01022 
01023         fractional = abs(fractional);
01024 
01025         if( fractional < 100) {
01026             if( fractional < 10)
01027                 s << "00";
01028             else
01029                 s << 0;
01030         }
01031 
01032         s << fractional;
01033 
01034         return s.str();
01035     }
01036     case TYPE_CALLABLE:
01037         return "(object)";
01038     case TYPE_LIST: {
01039         std::string res = "";
01040         for(size_t i=0; i<list_->elements.size(); ++i) {
01041             const variant& var = list_->elements[i];
01042             if(!res.empty()) {
01043                 res += ", ";
01044             }
01045 
01046             res += var.string_cast();
01047         }
01048 
01049         return res;
01050     }
01051     case TYPE_MAP: {
01052         std::string res = "";
01053         for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
01054             if(!res.empty()) {
01055                 res += ",";
01056             }
01057             res += i->first.string_cast();
01058             res += "->";
01059             res += i->second.string_cast();
01060         }
01061         return res;
01062     }
01063 
01064     case TYPE_STRING:
01065         return string_->str;
01066     default:
01067         assert(false);
01068         return "invalid";
01069     }
01070 }
01071 
01072 std::string variant::to_debug_string(std::vector<const game_logic::formula_callable*>* seen, bool verbose) const
01073 {
01074     std::vector<const game_logic::formula_callable*> seen_stack;
01075     if(!seen) {
01076         seen = &seen_stack;
01077     }
01078 
01079     std::ostringstream s;
01080     switch(type_) {
01081     case TYPE_NULL:
01082         s << "(null)";
01083     case TYPE_INT:
01084         s << int_value_;
01085         break;
01086     case TYPE_DECIMAL: {
01087         int fractional = decimal_value_ % 1000;
01088         int integer = (decimal_value_ - fractional) / 1000;
01089 
01090         s << integer << ".";
01091 
01092         fractional = abs(fractional);
01093 
01094         if( fractional < 100) {
01095             if( fractional < 10)
01096                 s << "00";
01097             else
01098                 s << 0;
01099         }
01100 
01101         s << fractional;
01102 
01103         break;
01104     }
01105     case TYPE_LIST: {
01106         s << "[";
01107         for(size_t n = 0; n != num_elements(); ++n) {
01108             if(n != 0) {
01109                 s << ", ";
01110             }
01111 
01112             s << operator[](n).to_debug_string(seen, verbose);
01113         }
01114         s << "]";
01115         break;
01116     }
01117     case TYPE_CALLABLE: {
01118         s << "{";
01119         if(std::find(seen->begin(), seen->end(), callable_) == seen->end()) {
01120             if(!verbose)
01121                 seen->push_back(callable_);
01122             std::vector<game_logic::formula_input> v = callable_->inputs();
01123             bool first = true;
01124             for(size_t i=0; i<v.size(); ++i) {
01125                 const game_logic::formula_input& input = v[i];
01126                 if(!first) {
01127                     s << ", ";
01128                 }
01129                 first = false;
01130                 s << input.name << " ";
01131                 if(input.access == game_logic::FORMULA_READ_WRITE) {
01132                     s << "(read-write) ";
01133                 } else if(input.access == game_logic::FORMULA_WRITE_ONLY) {
01134                     s << "(writeonly) ";
01135                 }
01136 
01137                 s << "-> " << callable_->query_value(input.name).to_debug_string(seen, verbose);
01138             }
01139         } else {
01140             s << "...";
01141         }
01142         s << "}";
01143         break;
01144     }
01145     case TYPE_MAP: {
01146         s << "[";
01147         bool first_time = true;
01148         for(std::map<variant,variant>::const_iterator i=map_->elements.begin(); i != map_->elements.end(); ++i) {
01149             if(!first_time) {
01150                 s << ",";
01151             }
01152             first_time = false;
01153             s << i->first.to_debug_string(seen, verbose);
01154             s << "->";
01155             s << i->second.to_debug_string(seen, verbose);
01156         }
01157         s << "]";
01158         break;
01159     }
01160     case TYPE_STRING: {
01161         s << "'" << string_->str << "'";
01162         break;
01163     }
01164     }
01165 
01166     return s.str();
01167 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:14 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs