00001
00020 #ifndef _ATTRIBUTE_H
00021 #define _ATTRIBUTE_H
00022
00023 #include <exception>
00024 #include <Vector.H>
00025 #include <string>
00026
00027 using namespace std;
00028
00029
00030 namespace xchen
00031 {
00032
00033 class Attribute
00034 {
00035 friend class Attributes;
00036
00037 string id;
00038 char const* type;
00039 void* val;
00040
00041 public:
00042 Attribute(Attribute const&);
00043 Attribute& operator=(Attribute const&);
00044
00045
00046 template<typename T>
00047 Attribute(string const& name, T const&v) : id(name), type(typeid(T).name()), val(new T(v)) { }
00048 Attribute(string const& name, type_info const& t) : id(name), type(t.name()), val(0) { }
00049 ~Attribute() { deallocate(); }
00050
00051 template<typename T>
00052 void SetValue(T const& v) { if(strcmp(typeid(T).name(),type)) throw "Attributes::SetValue() type mismatch!\n"; if(!val)val = new T(); *(T*)val = v; }
00053 void const* GetValue() { return val; }
00054 bool operator<(Attribute const& rhs) const { return id < rhs.id; }
00055
00056 friend istream& operator>> (istream& is, Attribute& a);
00057 friend ostream& operator<< (ostream& os, Attribute const& a);
00058
00059 private:
00060 Attribute(string const& name) : id(name), type(typeid(int).name()), val(0) { }
00061 Attribute(string const& name, char*) { throw "Attribute(string const&, char*) disabled, use Attribute(string const&, string const&) instead.\n"; }
00062
00063 void deallocate();
00064 void allocate(void* v);
00065 };
00066
00067
00068 class Attributes
00069 {
00070 public:
00071 template<typename T>
00072 void Register(string const& id, T const&v);
00073 void Register(string const& id, type_info const& t);
00074
00075 Attribute& operator[](string const& id);
00076
00077 void ReadFrom(int argc, char** argv);
00078 void ReadFrom(string const& str);
00079
00080 friend istream& operator>> (istream& is, Attributes&);
00081 friend ostream& operator<< (ostream& os, Attributes const&);
00082
00083 private:
00084 set<Attribute> attr;
00085 };
00086
00087
00088
00089
00090 inline Attribute :: Attribute(Attribute const& rhs) : id(rhs.id), type(rhs.type), val(0)
00091 {
00092 allocate(rhs.val);
00093 }
00094
00095 inline Attribute& Attribute :: operator=(Attribute const& rhs)
00096 {
00097 if(this != &rhs)
00098 {
00099 id = rhs.id;
00100 type = rhs.type;
00101 allocate(rhs.val);
00102 }
00103 return *this;
00104 }
00105
00106 inline void Attribute::deallocate()
00107 {
00108 if(!val) return;
00109
00110 if (! strcmp(type, typeid(char).name()) ) delete (char*)val;
00111 else if(! strcmp(type, typeid(int).name()) ) delete (int*)val;
00112 else if(! strcmp(type, typeid(double).name()) ) delete (double*)val;
00113 else if(! strcmp(type, typeid(dVector2D).name()) ) delete (dVector2D*)val;
00114 else if(! strcmp(type, typeid(dVector3D).name()) ) delete (dVector3D*)val;
00115 else if(! strcmp(type, typeid(dVector4D).name()) ) delete (dVector4D*)val;
00116 else if(! strcmp(type, typeid(dVector5D).name()) ) delete (dVector5D*)val;
00117 else if(! strcmp(type, typeid(iVector2D).name()) ) delete (iVector2D*)val;
00118 else if(! strcmp(type, typeid(iVector3D).name()) ) delete (iVector3D*)val;
00119 else if(! strcmp(type, typeid(iVector4D).name()) ) delete (iVector4D*)val;
00120 else if(! strcmp(type, typeid(iVector5D).name()) ) delete (iVector5D*)val;
00121 else if(! strcmp(type, typeid(string).name()) ) delete (string*)val;
00122 else { throw "supported attributes types are int, char, double, dVector[2-5]D, string\n"; }
00123 }
00124
00125
00126 inline void Attribute::allocate(void *v)
00127 {
00128 if(!v) return;
00129
00130 if (! strcmp(type, typeid(char).name()) ) { delete (char*)val; val = new char(*(char*)v); }
00131 else if(! strcmp(type, typeid(int).name()) ) { delete (int*)val; val = new int(*(int*)v); }
00132 else if(! strcmp(type, typeid(double).name()) ) { delete (double*)val; val = new double(*(double*)v); }
00133 else if(! strcmp(type, typeid(dVector2D).name()) ) { delete (dVector2D*)val; val = new dVector2D(*(dVector2D*)v); }
00134 else if(! strcmp(type, typeid(dVector3D).name()) ) { delete (dVector3D*)val; val = new dVector3D(*(dVector3D*)v); }
00135 else if(! strcmp(type, typeid(dVector4D).name()) ) { delete (dVector4D*)val; val = new dVector4D(*(dVector4D*)v); }
00136 else if(! strcmp(type, typeid(dVector5D).name()) ) { delete (dVector5D*)val; val = new dVector5D(*(dVector5D*)v); }
00137 else if(! strcmp(type, typeid(iVector2D).name()) ) { delete (iVector2D*)val; val = new iVector2D(*(iVector2D*)v); }
00138 else if(! strcmp(type, typeid(iVector3D).name()) ) { delete (iVector3D*)val; val = new iVector3D(*(iVector3D*)v); }
00139 else if(! strcmp(type, typeid(iVector4D).name()) ) { delete (iVector4D*)val; val = new iVector4D(*(iVector4D*)v); }
00140 else if(! strcmp(type, typeid(iVector5D).name()) ) { delete (iVector5D*)val; val = new iVector5D(*(iVector5D*)v); }
00141 else if(! strcmp(type, typeid(string).name()) ) { delete (string*)val; val = new string(*(string*)v); }
00142 else { throw "supported attributes types are int, char, double, dVector[2-5]D, string\n"; }
00143 }
00144
00145
00146
00147 inline void Attributes :: Register(string const& id, type_info const& t)
00148 {
00149 if(! attr.insert(Attribute(id, t)).second)
00150 cerr << "Registration Attribute \"" << id << "\" failed: an attribute of the same id has already registered.\n";
00151 }
00152
00153 template<typename T>
00154 inline void Attributes :: Register(string const& id, T const&v)
00155 {
00156 pair<set<Attribute>::iterator, bool> result = attr.insert(Attribute(id, typeid(T)));
00157 if(!result.second)
00158 cerr << "Registration Attribute \"" << id << "\" failed: an attribute of the same id has already registered.\n";
00159 else
00160 {
00161 ((Attribute&)(*result.first)).SetValue(v);
00162 }
00163
00164 }
00165
00166 inline Attribute& Attributes :: operator[](string const& id)
00167 {
00168 set<Attribute>::iterator itr = attr.find(Attribute(id));
00169 if(itr == attr.end())
00170 throw "attribute " + id + " unregistered.\n";
00171 return (Attribute&)(*itr);
00172 }
00173
00174
00175 typedef Attributes CommandLineArguments;
00176 }
00177
00178
00179
00180 #endif