Sirikata
libcore/include/sirikata/core/options/OptionValue.hpp
Go to the documentation of this file.
00001 /*  Sirikata Configuration Options -- Sirikata Options
00002  *  OptionValue.hpp
00003  *
00004  *  Copyright (c) 2009, Daniel Reiter Horn
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 
00033 #ifndef _SIRIKATA_OPTIONVALUE_HPP_
00034 #define _SIRIKATA_OPTIONVALUE_HPP_
00035 
00036 #include <sirikata/core/util/Any.hpp>
00037 
00038 namespace Sirikata {
00039 class OptionSet;
00040 
00041 // Strings
00042 
00043 template <class T> class OptionValueType {public:
00044     static Any lexical_cast(const std::string &value){
00045         T retval=T();
00046         std::istringstream ss(value);
00047         ss>>retval;
00048         return retval;
00049     }
00050 };
00051 template <> class OptionValueType<std::string> {public:
00052     static Any lexical_cast(const std::string &value){
00053         return value;
00054     }
00055 };
00056 
00057 // Maps
00058 
00059 template <class T> class OptionValueMap {public:
00061     static Any lexical_cast(const std::string &value){
00062         T retval;
00063         std::string::size_type where=0,oldwhere=0;
00064         while((where=value.find(':',oldwhere))!=std::string::npos) {
00065             std::string key=value.substr(oldwhere,where-oldwhere);
00066             oldwhere=where+1;
00067             where=value.find('{',oldwhere);
00068             if (where!=std::string::npos) {
00069                 int count=1;
00070                 std::string::size_type value_begin=oldwhere=where+1;
00071                 while ((where=value.find_first_of("{}",oldwhere))!=std::string::npos) {
00072                     if (value[where]=='}')
00073                         --count;
00074                     else
00075                         ++count;
00076                     oldwhere=where+1;
00077                     if (count==0){
00078                         std::string val=value.substr(value_begin,where-value_begin);
00079                         retval[key]=val;
00080                         break;
00081                     }
00082                 }
00083             }
00084             where=value.find(',',oldwhere);
00085             if (where==std::string::npos) break;
00086             oldwhere=where+1;
00087         }
00088         return retval;
00089     }
00090 };
00091 
00092 template <> class OptionValueType<std::map<std::string,std::string> > :public OptionValueMap<std::map<std::string,std::string> > {public:
00093 };
00094 template <> class OptionValueType<std::tr1::unordered_map<std::string,std::string> > :public OptionValueMap<std::tr1::unordered_map<std::string,std::string> > {public:
00095 };
00096 
00097 // Lists
00098 
00099 template <class T>
00100 class OptionValueList {
00101 public:
00103     static Any lexical_cast(const std::string &value){
00104         T retval;
00105 
00106         // Strip any [] around the list
00107         int32 list_start = 0, list_end = value.size();
00108         while(list_start < (int32)value.size()) {
00109             if (value[list_start] == '[') {
00110                 list_start++;
00111                 break;
00112             }
00113             else if (value[list_start] == ' ' || value[list_start] == '\t')
00114                 list_start++;
00115             else
00116                 break;
00117         }
00118         while(list_end > 0) {
00119             if (value[list_end-1] == ']') {
00120                 list_end--;
00121                 break;
00122             }
00123             else if (value[list_end-1] == ' ' || value[list_end-1] == '\t')
00124                 list_end--;
00125             else
00126                 break;
00127         }
00128 
00129         if (list_end - list_start <= 0) return retval;
00130 
00131         int32 comma = list_start, last_comma = list_start-1;
00132 
00133         while(true) {
00134             comma = (int32)value.find(',', last_comma+1);
00135             if (comma > list_end || comma == (int32)std::string::npos)
00136                 comma = list_end;
00137             std::string elem = value.substr(last_comma+1, (comma-(last_comma+1)));
00138             if (elem.size() > 0)
00139                 retval.push_back(elem);
00140 
00141             // If we hit the end of the string, finish up
00142             if (comma >= list_end)
00143                 break;
00144 
00145             last_comma = comma;
00146         }
00147         return retval;
00148     }
00149 };
00150 
00151 template <> class OptionValueType<std::vector<std::string> > :public OptionValueList<std::vector<std::string> > {public:
00152 };
00153 template <> class OptionValueType<std::list<std::string> > :public OptionValueList<std::list<std::string> > {public:
00154 };
00155 
00156 // Bool
00157 
00158 template <> class OptionValueType<bool> {public:
00159     static Any lexical_cast(const std::string &value){
00160         bool retval=false;
00161         if (value.size()){
00162             if (value[0]=='T'||value[0]=='t'||value[0]=='1'||value[0]=='Y'||value[0]=='y')
00163                 retval=true;
00164         }
00165         return retval;
00166     }
00167 };
00168 class OptionRegistration;
00169 
00173 class OptionValue{
00174     Any mValue;
00175     std::string mDefaultValue;
00176     const char *mDefaultChar;
00177     const char* mDescription;
00178     std::tr1::function<Any(std::string)> mParser;
00179     std::tr1::function<void(const std::string&,Any,Any)>mChangeFunction;
00180     const char* mName;
00181 
00182     static void noop(const std::string&,Any ,Any) {
00183 
00184     }
00186     friend class OptionRegistration;
00188     friend class OptionSet;
00189 
00190 public:
00191 
00192     const Any*operator->()const {
00193         return &mValue;
00194     }
00195     Any*operator->() {
00196         return &mValue;
00197     }
00198     const Any*get()const {
00199         return &mValue;
00200     }
00201     Any* get() {
00202         return &mValue;
00203     }
00204     template <class T> T&as(){return mValue.as<T>();}
00205     template <class T> const T&as()const{return mValue.as<T>();}
00206     template <class T> T&unsafeAs(){return mValue.unsafeAs<T>();}
00207     template <class T> const T&unsafeAs()const{return mValue.unsafeAs<T>();}
00208     const char*description() const{
00209         return mDescription;
00210     }
00211     const char *defaultValue() const{
00212         return mDefaultChar?mDefaultChar:mDefaultValue.c_str();
00213     }
00215     OptionValue& operator=(const OptionValue&other);
00216 
00217     OptionValue() {
00218         mDefaultChar=NULL;
00219         mDescription="";mName="";
00220         mChangeFunction=NULL;
00221         mParser=NULL;
00222     }
00231     template<class T>OptionValue(const char*option, const std::string&defaultValue, T type, const char*description, OptionValue**pointer=NULL):mDefaultChar(NULL){
00232         mParser=std::tr1::function<Any(std::string)>(&T::lexical_cast);
00233         mName=option;
00234         mDefaultValue=defaultValue;
00235         mDescription=description;
00236         mChangeFunction=std::tr1::function<void(const std::string&, Any, Any)>(&OptionValue::noop);
00237         if (pointer)
00238             *pointer=this;
00239     }
00249     template<class T>OptionValue(const char* option, const std::string&defaultValue, T xtype, const char*description, std::tr1::function<void(const std::string&,Any,Any)>&changeFunction, OptionValue**pointer=NULL) :mDefaultChar(NULL){
00250         mParser=std::tr1::function<Any(std::string)>(&T::lexical_cast);
00251         mName=option;
00252         mDescription=description;
00253         mDefaultValue=defaultValue;
00254         mChangeFunction=std::tr1::function<void(const std::string&, Any, Any)>(&OptionValue::noop);
00255         if (pointer)
00256             *pointer=this;
00257     }
00266     OptionValue(const char* option, const std::string&defaultValue, const char *description, const std::tr1::function<Any(std::string)>& parser, OptionValue**pointer=NULL) :mDefaultChar(NULL){
00267         mParser=parser;
00268         mName=option;
00269         mDescription=description;
00270         mDefaultValue=defaultValue;
00271         mChangeFunction=&OptionValue::noop;
00272         if (pointer)
00273             *pointer=this;
00274     }
00284     OptionValue(const char* option, const std::string&defaultValue, const char* description, const std::tr1::function<Any(std::string)>& parser,  const std::tr1::function<void(const std::string&, Any, Any)> &changeFunction, OptionValue**pointer=NULL) :mDefaultChar(NULL){
00285         mParser=parser;
00286         mName=option;
00287         mDescription=description;
00288         mDefaultValue=defaultValue;
00289         mChangeFunction=changeFunction;
00290         if (pointer)
00291             *pointer=this;
00292     }
00293 
00294 
00295 
00296 
00297 
00298 
00299 
00308     template<class T>OptionValue(const char*option, const char*defaultValue, T type, const char*description, OptionValue**pointer=NULL){
00309         mParser=std::tr1::function<Any(std::string)>(&T::lexical_cast);
00310         mName=option;
00311         mDefaultChar=defaultValue;
00312         mDescription=description;
00313         mChangeFunction=std::tr1::function<void(const std::string&, Any, Any)>(&OptionValue::noop);
00314         if (pointer)
00315             *pointer=this;
00316     }
00326     template<class T>OptionValue(const char* option, const char*defaultValue, T xtype, const char*description, std::tr1::function<void(const std::string&,Any,Any)>&changeFunction, OptionValue**pointer=NULL) {
00327         mParser=std::tr1::function<Any(std::string)>(&T::lexical_cast);
00328         mName=option;
00329         mDescription=description;
00330         mDefaultChar=defaultValue;
00331         mChangeFunction=std::tr1::function<void(const std::string&, Any, Any)>(&OptionValue::noop);
00332         if (pointer)
00333             *pointer=this;
00334     }
00343     OptionValue(const char* option, const char*defaultValue, const char *description, const std::tr1::function<Any(std::string)>& parser, OptionValue**pointer=NULL) {
00344         mParser=parser;
00345         mName=option;
00346         mDescription=description;
00347         mDefaultChar=defaultValue;
00348         mChangeFunction=&OptionValue::noop;
00349         if (pointer)
00350             *pointer=this;
00351     }
00361     OptionValue(const char* option, const char*defaultValue, const char* description, const std::tr1::function<Any(std::string)>& parser,  const std::tr1::function<void(const std::string&, Any, Any)> &changeFunction, OptionValue**pointer=NULL) {
00362         mParser=parser;
00363         mName=option;
00364         mDescription=description;
00365         mDefaultChar=defaultValue;
00366         mChangeFunction=changeFunction;
00367         if (pointer)
00368             *pointer=this;
00369     }
00370 
00371 
00372 
00373 };
00374 }
00375 #endif //_SIRIKATA_OPTIONVALUE_HPP_