![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* js_registry.h -*- C++ -*- 00002 Jeremy Barnes, 27 July 2010 00003 Copyright (c) 2010 Datacratic. All rights reserved. 00004 00005 Registry for JS classes. 00006 */ 00007 00008 #pragma once 00009 00010 #include <map> 00011 #include <vector> 00012 #include <v8/v8.h> 00013 #include <boost/function.hpp> 00014 #include "jml/utils/exc_assert.h" 00015 #include "jml/arch/demangle.h" 00016 #include "jml/arch/rtti_utils.h" 00017 #include "jml/arch/backtrace.h" 00018 #include "js_value.h" 00019 #include <boost/shared_ptr.hpp> 00020 #include <iostream> 00021 00022 00023 namespace Datacratic { 00024 namespace JS { 00025 00026 00027 typedef boost::function<void (const v8::Persistent<v8::FunctionTemplate> &, 00028 const std::string & name, 00029 const v8::Handle<v8::Object> &)> SetupFunction; 00030 typedef boost::function<void ()> InitFunction; 00031 00032 00033 enum OnConstructorError { 00034 THROW_ON_ERROR, 00035 RETURN_NULL_ON_ERROR 00036 }; 00037 00038 const std::type_info & getWrapperTypeInfo(v8::Handle<v8::Value> obj); 00039 00040 00041 /*****************************************************************************/ 00042 /* REGISTRY */ 00043 /*****************************************************************************/ 00044 00045 struct Registry { 00046 00047 Registry(); 00048 00049 ~Registry(); 00050 00051 const v8::Persistent<v8::FunctionTemplate> & 00052 operator [] (const std::string & name) const; 00053 00057 void init(v8::Handle<v8::Object> target, const std::string & module); 00058 00059 00063 void import(const Registry & other, const std::string & name); 00064 00065 bool empty() const { return templates.empty(); } 00066 00067 v8::Local<v8::Function> 00068 getConstructor(const std::string & cls) const; 00069 00070 v8::Local<v8::Object> 00071 constructInstance(const std::string & cls, 00072 OnConstructorError e = THROW_ON_ERROR) const; 00073 00074 v8::Local<v8::Object> 00075 constructInstance(const std::string & cls, 00076 const v8::Arguments & args, 00077 OnConstructorError e = THROW_ON_ERROR) const; 00078 00079 v8::Local<v8::Object> 00080 constructInstance(const std::string & cls, 00081 int argc, v8::Handle<v8::Value> * argv, 00082 OnConstructorError e = THROW_ON_ERROR) const; 00083 00084 00085 void introduce(const std::string & name, 00086 const std::string & module, 00087 const InitFunction init, 00088 const std::string & base = ""); 00089 00090 void get_to_know(const std::string & name, 00091 const std::string & module, 00092 const v8::Persistent<v8::FunctionTemplate> & tmpl, 00093 SetupFunction setup); 00094 00099 typedef v8::Local<v8::Object> (* ConstructWrapperFunction) (void *, const void *); 00100 00101 typedef void (* UnwrapFunction) (const v8::Handle<v8::Value> &, void *, 00102 const std::type_info &); 00103 00105 template<typename Shared, typename Wrapper> 00106 void isWrapper(ConstructWrapperFunction construct, 00107 UnwrapFunction unwrap) 00108 { 00109 const std::type_info * ti = &typeid(Shared); 00110 00111 //using namespace std; 00112 //cerr << ML::type_name<Wrapper>() << " is wrapper for " 00113 // << ML::type_name<Shared>() << endl; 00114 00115 if (type_entries.count(ti)) 00116 throw ML::Exception("double wrap of type " 00117 + ML::type_name<Shared>() 00118 + ": " + type_entries[ti].wrapper 00119 + " and " + ML::type_name<Wrapper>()); 00120 00121 type_entries[ti].construct = construct; 00122 type_entries[ti].wrapper = ML::type_name<Wrapper>(); 00123 00124 ti = &typeid(Wrapper); 00125 if (type_entries.count(ti)) 00126 throw ML::Exception("double wrap of type " 00127 + ML::type_name<Wrapper>() 00128 + ": " + type_entries[ti].wrapper 00129 + " and " + ML::type_name<Wrapper>()); 00130 00131 type_entries[ti].unwrap = unwrap; 00132 } 00133 00138 template<typename Base, typename Derived> 00139 void isBase() 00140 { 00141 #if 0 00142 using namespace std; 00143 cerr << ML::type_name<Derived>() 00144 << " derives from " << ML::type_name<Base>() 00145 << endl; 00146 #endif 00147 } 00148 00174 template<typename Base> 00175 v8::Local<v8::Object> 00176 getWrapper(const std::shared_ptr<Base> & object) const 00177 { 00178 if (!object) { 00179 //ML::backtrace(); 00180 throw ML::Exception("getWrapper(): no object"); 00181 } 00182 00183 const std::type_info * ti = &typeid(*object); 00184 00185 // Is there a direct wrapper function? 00186 auto it = type_entries.find(ti); 00187 if (it != type_entries.end() && ti != &typeid(Base)) { 00188 const TypeEntry & entry = it->second; 00189 00190 // Offset the pointer to do the equivalent of a dynamic_cast 00191 const void * ptr = ML::is_convertible(*object, *ti); 00192 00193 // Create a stack-based shared ptr to be on the stack 00194 std::shared_ptr<Base> sp = object; 00195 00196 // Construct the instance 00197 return entry.construct(&sp, ptr); 00198 } 00199 00200 // No direct wrapper. Look for the most specific type under Base 00201 // that matches. 00202 00203 // ... 00204 // TODO: do 00205 00206 // No more specific wrapper. We use the base handler 00207 ti = &typeid(Base); 00208 it = type_entries.find(ti); 00209 00210 if (it != type_entries.end()) { 00211 const TypeEntry & entry = it->second; 00212 00213 // No dynamic cast because the pointer is already there 00214 void * ptr = (void *)(object.get()); 00215 00216 // Create a stack-based shared ptr to be on the stack 00217 std::shared_ptr<Base> sp = object; 00218 00219 // Construct the instance 00220 return entry.construct(&sp, ptr); 00221 } 00222 00223 throw ML::Exception("don't know how to wrap a " 00224 + ML::type_name(*object)); 00225 } 00226 00227 #if 1 00228 00231 template<typename Object> 00232 std::shared_ptr<Object> 00233 getObject(v8::Local<v8::Value> wrapped) const 00234 { 00235 const std::type_info & wrapperType 00236 = getWrapperTypeInfo(wrapped); 00237 00238 const std::type_info & objectType = typeid(Object); 00239 00240 auto it = type_entries.find(&wrapperType); 00241 if (it == type_entries.end()) 00242 throw ML::Exception("Can't convert wrapper of type " 00243 + ML::type_name(wrapperType) 00244 + " to object of type " 00245 + ML::type_name(objectType)); 00246 00247 // Look up how to get an object out of it 00248 std::shared_ptr<Object> result; 00249 it->second.unwrap(wrapped, &result, objectType); 00250 00251 return result; 00252 } 00253 00254 template<typename Object> 00255 std::shared_ptr<Object> 00256 getObject(v8::Handle<v8::Value> wrapped) const 00257 { 00258 const std::type_info & wrapperType 00259 = getWrapperTypeInfo(wrapped); 00260 00261 const std::type_info & objectType = typeid(Object); 00262 00263 auto it = type_entries.find(&wrapperType); 00264 if (it == type_entries.end()) 00265 throw ML::Exception("Can't convert wrapper of type " 00266 + ML::type_name(wrapperType) 00267 + " to object of type " 00268 + ML::type_name(objectType)); 00269 00270 // Look up how to get an object out of it 00271 std::shared_ptr<Object> result; 00272 it->second.unwrap(wrapped, &result, objectType); 00273 00274 return result; 00275 } 00276 #endif 00277 00278 private: 00280 struct TypeEntry { 00281 TypeEntry() 00282 : construct(0), unwrap(0) 00283 { 00284 } 00285 00286 ConstructWrapperFunction construct; 00287 UnwrapFunction unwrap; 00288 std::string wrapper; 00289 }; 00290 00291 typedef std::map<const std::type_info *, TypeEntry> TypeEntries; 00292 TypeEntries type_entries; 00293 00294 struct Entry { 00295 Entry() 00296 : setup(0), imported(false) 00297 { 00298 } 00299 00300 std::string name; 00301 std::string base; 00302 std::string module; 00303 InitFunction init; 00304 v8::Persistent<v8::FunctionTemplate> tmpl; 00305 SetupFunction setup; 00306 bool imported; 00307 }; 00308 00309 int num_uninitialized; 00310 00311 std::map<std::string, Entry> templates; 00312 00313 void initialize(); 00314 void do_initialize(const std::string & name); 00315 }; 00316 00317 00318 00319 template<typename Derived, typename DerivedWrapper, typename Base> 00320 v8::Handle<v8::Object> 00321 doDerived(Registry & registry, 00322 const std::shared_ptr<Base> & handler, 00323 const char * name) 00324 { 00325 v8::Handle<v8::Object> result; 00326 00327 std::shared_ptr<Derived> cast 00328 = std::dynamic_pointer_cast<Derived>(handler); 00329 00330 if (cast) { 00331 result = registry.constructInstance(name); 00332 ExcAssert(!result.IsEmpty()); 00333 DerivedWrapper::setShared(result, cast); 00334 } 00335 00336 return result; 00337 } 00338 00339 extern Registry registry; 00340 00341 } // namespace JS 00342 } // namespace Datacratic