00001
00002
00003 #include "cppscript"
00004 #include "dynamic/extensions.hpp"
00005
00006 #include <vector>
00007 #include <sstream>
00008 #include <cstring>
00009
00010
00011 dynamic::pickler::pickler(std::ostream & output) :
00012 m_output(output)
00013 {
00014 }
00015
00016
00017 std::string dynamic::pickle(const var & v)
00018 {
00019 std::ostringstream ss;
00020 pickler p(ss);
00021 p.write_object(v);
00022 return ss.str();
00023 }
00024
00025
00026 var dynamic::unpickle(const std::string & s)
00027 {
00028 std::istringstream ss;
00029 ss.rdbuf()->str(s);
00030
00031 return unpickler(ss).read_object();
00032 }
00033
00034
00035 void var_impl::pickle(pickler & p)
00036 {
00037 throw not_supported(this, "pickle");
00038 }
00039
00040
00041 void var_impl::unpickle(unpickler & u)
00042 {
00043 throw not_supported(this, "unpickle");
00044 }
00045
00046
00047 void dynamic::pickler::write_object(const var & o)
00048 {
00049 shared_var_impl * shared = o.impl().shared_var();
00050
00051 if(shared)
00052 {
00053 object_map::iterator i = m_objects.find(shared);
00054 if(i == m_objects.end())
00055 {
00056 std::size_t id = m_objects.size();
00057 m_objects[shared] = id;
00058 shared->pickle(*this);
00059 }
00060 else
00061 {
00062
00063 write_object_type(cmp_reference);
00064 write_int(int(i->second));
00065 }
00066 }
00067 else
00068 {
00069 o.impl().pickle(*this);
00070 }
00071 }
00072
00073
00074 void dynamic::pickler::write_object_type(var_cmp_index code)
00075 {
00076 write_int(code+'A');
00077 }
00078
00079
00080 void dynamic::pickler::write_int(int i)
00081 {
00082 if(i>0 && i<128 && isalpha(i))
00083 m_output << char(i);
00084 else
00085 m_output << i << ';';
00086 }
00087
00088
00089 void dynamic::pickler::write_size(std::size_t i)
00090 {
00091 m_output << i << ';';
00092 }
00093
00094
00095 void dynamic::pickler::write_double(double d)
00096 {
00097 m_output << d << ';';
00098 }
00099
00100
00101 dynamic::unpickler::unpickler(std::istream & input) : m_input(input)
00102 {
00103 }
00104
00105
00106 var dynamic::unpickler::read_object()
00107 {
00108 var_cmp_index type = var_cmp_index(read_int()-'A');
00109 var result;
00110
00111 switch(type)
00112 {
00113 case cmp_reference:
00114 {
00115 std::size_t id = read_int();
00116 if(id>=m_objects.size()) throw invalid_string();
00117 return m_objects[id];
00118 }
00119 break;
00120
00121 case cmp_function_0:
00122 return (f0)read_function_pointer();
00123
00124 case cmp_function_v0:
00125 return (vf0)read_function_pointer();
00126
00127 case cmp_function_1:
00128 return (f1)read_function_pointer();
00129
00130 case cmp_function_v1:
00131 return (vf1)read_function_pointer();
00132
00133 case cmp_function_2:
00134 return (f2)read_function_pointer();
00135
00136 case cmp_function_v2:
00137 return (vf2)read_function_pointer();
00138
00139 case cmp_function_3:
00140 return (f3)read_function_pointer();
00141
00142 case cmp_function_v3:
00143 return (vf3)read_function_pointer();
00144
00145 case cmp_function_4:
00146 return (f4)read_function_pointer();
00147
00148 case cmp_function_v4:
00149 return (vf4)read_function_pointer();
00150
00151 case cmp_function_5:
00152 return (f5)read_function_pointer();
00153
00154 case cmp_function_v5:
00155 return (vf5)read_function_pointer();
00156
00157 case cmp_function_6:
00158 return (f6)read_function_pointer();
00159
00160 case cmp_function_v6:
00161 return (vf6)read_function_pointer();
00162 case cmp_function_7:
00163 return (f7)read_function_pointer();
00164
00165 case cmp_function_v7:
00166 return (vf7)read_function_pointer();
00167
00168 case cmp_function_8:
00169 return (f8)read_function_pointer();
00170 case cmp_function_v8:
00171 return (vf8)read_function_pointer();
00172
00173 case cmp_function_9:
00174 return (f9)read_function_pointer();
00175
00176 case cmp_function_v9:
00177 return (vf9)read_function_pointer();
00178
00179 case cmp_function_10:
00180 return (f10)read_function_pointer();
00181
00182 case cmp_function_v10:
00183 return (vf10)read_function_pointer();
00184
00185 case cmp_bind:
00186 result = internal::bind(read_int());
00187 break;
00188
00189 case cmp_dispatcher:
00190 result = dispatcher(null);
00191 break;
00192
00193 default:
00194 result = unpickle_type(type);
00195 }
00196
00197 shared_var_impl * sh = result.impl().shared_var();
00198 if(sh) m_objects.push_back(sh);
00199 result.impl().unpickle(*this);
00200
00201 return result;
00202 }
00203
00204
00205 void * dynamic::unpickler::read_function_pointer()
00206 {
00207 return internal::lookup_function( read_string().c_str() );
00208 }
00209
00210
00211 int dynamic::unpickler::read_int()
00212 {
00213 if(isalpha(m_input.peek()))
00214 {
00215 char x;
00216 m_input >> x;
00217 return x;
00218 }
00219 else
00220 {
00221 char c;
00222 int x;
00223 m_input >> x >> c;
00224 return x;
00225 }
00226 }
00227
00228
00229 std::size_t dynamic::unpickler::read_size()
00230 {
00231 char c;
00232 std::size_t x;
00233 m_input >> x >> c;
00234 return x;
00235 }
00236
00237
00238 double dynamic::unpickler::read_double()
00239 {
00240 double x;
00241 char c;
00242 m_input >> x >> c;
00243 return x;
00244 }
00245
00246
00247 void dynamic::pickler::write_string(std::string const & str)
00248 {
00249 write_int(int(str.size()));
00250 for(std::string::const_iterator i=str.begin(); i!=str.end(); ++i)
00251 write_int(*i);
00252 }
00253
00254
00255 std::string dynamic::unpickler::read_string()
00256 {
00257 std::string result;
00258 result.resize(read_int());
00259 for(std::string::iterator i=result.begin(); i!=result.end(); ++i)
00260 *i = read_int();
00261 return result;
00262 }
00263
00264
00265 namespace
00266 {
00267 class function_lut
00268 {
00269 function_lut() { }
00270
00271 struct name_comparator
00272 {
00273 bool operator()(const char *a, const char *b) const { return strcmp(a,b)<0; }
00274 };
00275
00276
00277 std::map<void*, const char*> m_function_name;
00278 std::map<const char*, void*, name_comparator> m_function_address;
00279
00280 public:
00281
00282 static function_lut & singleton()
00283 {
00284 static function_lut lut;
00285 return lut;
00286 }
00287
00288 bool add(const char * name, void * address)
00289 {
00290 if( m_function_address.find(name) != m_function_address.end())
00291 std::cerr << "Warning: function name " << name << " is registered twice" << std::endl;
00292 m_function_name[address]=name;
00293 m_function_address[name]=address;
00294 return true;
00295 }
00296
00297 void * lookup(const char * name) const
00298 {
00299 std::map<const char*, void*, name_comparator>::const_iterator i=m_function_address.find(name);
00300 if( i == m_function_address.end() ) throw exception("function not found");
00301 return i->second;
00302 }
00303
00304 const char * lookup(void * address) const
00305 {
00306 std::map<void*, const char*>::const_iterator i=m_function_name.find(address);
00307 if( i == m_function_name.end() ) throw exception("function not found");
00308 return i->second;
00309 }
00310 };
00311 }
00312
00313
00314 bool dynamic::internal::register_function(const char * name, void * address)
00315 {
00316 return function_lut::singleton().add(name, address);
00317 }
00318
00319
00320 const char * dynamic::internal::lookup_function(void * address)
00321 {
00322 return function_lut::singleton().lookup(address);
00323 }
00324
00325
00326 void * dynamic::internal::lookup_function(const char * name)
00327 {
00328 return function_lut::singleton().lookup(name);
00329 }
00330
00331
00332 namespace
00333 {
00334 class pickle_types
00335 {
00336 std::map<var_cmp_index, var> m_types;
00337
00338 pickle_types() { }
00339
00340 public:
00341 static pickle_types & singleton()
00342 {
00343 static pickle_types s;
00344 return s;
00345 }
00346
00347 void add(var_cmp_index i, const var&t)
00348 {
00349 m_types[i] = t;
00350 }
00351
00352 var get(var_cmp_index i) const
00353 {
00354 std::map<var_cmp_index, var>::const_iterator it = m_types.find(i);
00355
00356
00357 if(it == m_types.end()) throw invalid_string();
00358
00359 return +it->second;
00360 }
00361 };
00362 }
00363
00364
00365 void dynamic::register_pickle_type(var_cmp_index i, const var & t)
00366 {
00367 pickle_types::singleton().add(i,t);
00368 }
00369
00370
00371 var dynamic::unpickle_type(var_cmp_index i)
00372 {
00373 return pickle_types::singleton().get(i);
00374 }