00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef PROGRAM_OPTIONS_TYPED_VALUE_H_INCLUDED
00023 #define PROGRAM_OPTIONS_TYPED_VALUE_H_INCLUDED
00024 #ifdef _MSC_VER
00025 #pragma warning (disable : 4786)
00026 #pragma warning (disable : 4503)
00027 #pragma warning (disable : 4200)
00028 #endif
00029 #include "value.h"
00030 #include "string_convert.h"
00031 #include "detail/notifier.h"
00032 #include "errors.h"
00033 #include <memory>
00034 namespace ProgramOptions { namespace detail {
00035 template <class T>
00036 struct Parser { typedef bool (*type)(const std::string&, T&); };
00037 }
00038 using bk_lib::string_cast;
00040
00042 struct ValueMappingBase : private std::vector<std::pair<const char*, int> > {
00043 typedef std::vector<std::pair<const char*, int> > base_type;
00044 using base_type::size;
00045 using base_type::empty;
00046 void add(const char* strVal, int eVal){ push_back(value_type(strVal, eVal)); }
00047 const int* get(const char* strVal) const {
00048 for (const_iterator it = begin(), end = this->end(); it != end; ++it) {
00049 if (strcasecmp(strVal, it->first) == 0) { return &it->second; }
00050 }
00051 return 0;
00052 }
00053 };
00054 template <class T>
00055 struct ValueMapping : ValueMappingBase {
00056 typedef ValueMapping this_type;
00057 typedef ValueMappingBase base_type;
00058 using base_type::get;
00059 this_type& operator()(const char* strVal, T eVal){ base_type::add(strVal, static_cast<int>(eVal)); return *this; }
00060 static ValueMapping& instance() { static ValueMapping m; return m; }
00061 operator typename detail::Parser<T>::type() { return &parse<T>; }
00062 operator typename detail::Parser<int>::type() { return &parse<int>; }
00063 template <class U>
00064 static bool parse(const std::string& value, U& out){
00065 const ValueMappingBase& m = ValueMapping::instance();
00066 if (const int* x = m.get(value.c_str())) { out = static_cast<U>(*x); return true; }
00067 return false;
00068 }
00069 private:
00070 ValueMapping() {}
00071 };
00072 template <class T> ValueMapping<T>& values() { return ValueMapping<T>::instance(); }
00074
00076 template <class T>
00077 class StoredValue : public Value {
00078 public:
00079 typedef typename detail::Parser<T>::type parser_type;
00080 StoredValue(T& var, parser_type p)
00081 : Value(0)
00082 , address_(&var)
00083 , parser_(p) {
00084 this->setProperty(Value::property_location);
00085 }
00086 bool doParse(const std::string&, const std::string& value) {
00087 return this->parser_(value, *address_);
00088 }
00089 protected:
00090 T* address_;
00091 parser_type parser_;
00092 };
00094
00096 template <class T>
00097 struct DefaultCreator {
00098 static T* create() { return new T(); }
00099 };
00100 template <class T>
00101 class NotifiedValue : public Value {
00102 public:
00103 typedef typename detail::Parser<T>::type parser_type;
00104 typedef detail::Notifier<const T*> notifier_type;
00105 NotifiedValue(T* (*cf)(), const notifier_type& n, parser_type p)
00106 : Value(0)
00107 , parser_(p)
00108 , notify_(n) {
00109 value_.create = cf;
00110 }
00111 NotifiedValue<T>* storeTo(T& obj) {
00112 value_.address = &obj;
00113 this->setProperty(Value::property_location);
00114 return this;
00115 }
00116 bool doParse(const std::string& name, const std::string& value) {
00117 bool ret;
00118 T* pv = 0;
00119 std::auto_ptr<T> holder;
00120 if (this->hasProperty(Value::property_location)) {
00121 pv = value_.address;
00122 }
00123 else {
00124 holder.reset(value_.create());
00125 pv = holder.get();
00126 }
00127 ret = this->parser_(value, *pv);
00128 if (ret && notify_.notify(name, pv)) {
00129 this->storeTo(*pv);
00130 holder.release();
00131 }
00132 return ret;
00133 }
00134 protected:
00135 union {
00136 T* address;
00137 T* (*create)();
00138 } value_;
00139 parser_type parser_;
00140 notifier_type notify_;
00141 };
00143
00145 class CustomValue : public Value {
00146 public:
00147 typedef detail::Notifier<const std::string&> notifier_type;
00148 CustomValue(const notifier_type& n)
00149 : Value(0)
00150 , notify_(n) { }
00151 bool doParse(const std::string& name, const std::string& value) {
00152 return notify_.notify(name, value);
00153 }
00154 protected:
00155 notifier_type notify_;
00156 };
00158
00160 #define LIT_TO_STRING_X(lit) #lit
00161
00162 #define LIT_TO_STRING(lit) LIT_TO_STRING_X(lit)
00163 struct FlagAction {
00164 typedef detail::Parser<bool>::type parser_t;
00165 static inline bool store_true(const std::string& v, bool& b) {
00166 if (v.empty()) { return (b = true); }
00167 return string_cast<bool>(v, b);
00168 }
00169 static inline bool store_false(const std::string& v, bool& b) {
00170 bool temp;
00171 return store_true(v, temp) && ((b = !temp), true);
00172 }
00173 enum Action { act_store_true, act_store_false } act;
00174 FlagAction(Action a) : act(a) {}
00175 parser_t parser() const { return act == act_store_true ? store_true : store_false; }
00176 };
00177 static const FlagAction store_true( (FlagAction::act_store_true) );
00178 static const FlagAction store_false( (FlagAction::act_store_false));
00179
00189 template <class T>
00190 inline StoredValue<T>* storeTo(T& v, typename detail::Parser<T>::type p = &string_cast<T>) {
00191 return new StoredValue<T>(v, p);
00192 }
00193 inline StoredValue<bool>* flag(bool& b, FlagAction x = store_true) {
00194 return static_cast<StoredValue<bool>*>(storeTo(b, x.parser())->flag());
00195 }
00196
00215 template <class T, class ParamT>
00216 inline NotifiedValue<T>* notify(ParamT* p0, typename detail::Notify<const T*, ParamT>::type nf, typename detail::Parser<T>::type parser = &string_cast<T>) {
00217 return new NotifiedValue<T>(&DefaultCreator<T>::create, detail::Notifier<const T*>(p0, nf), parser);
00218 }
00219 template <class T, class ParamT>
00220 inline NotifiedValue<T>* storeNotify(T& obj, ParamT* p0, typename detail::Notify<const T*, ParamT>::type nf, typename detail::Parser<T>::type parser = &string_cast<T>) {
00221 return notify<T>(p0, nf, parser)->storeTo(obj);
00222 }
00223 template <class ParamT>
00224 inline NotifiedValue<bool>* flag(ParamT* p0, typename detail::Notify<const bool*, ParamT>::type nf, FlagAction a = store_true) {
00225 return static_cast<NotifiedValue<bool>*>(notify<bool>(p0, nf, a.parser())->flag());
00226 }
00227
00246 template <class ParamT>
00247 inline CustomValue* notify(ParamT* p0, typename detail::Notify<const std::string&, ParamT>::type nf) {
00248 return new CustomValue(detail::Notifier<const std::string&>(p0, nf));
00249 }
00250 }
00251 #endif