RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/js/js_registry.h
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
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator