RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/sigslot/slot.cc
00001 /* slot.cc
00002    Jeremy Barnes, 16 November 2010
00003    Copyright (c) 2010 Datacratic.  All rights reserved.
00004    
00005    Code to deal with slots.
00006 */
00007 
00008 #include "slot.h"
00009 #include "v8.h"
00010 #include "soa/js/js_utils.h"
00011 #include "soa/js/js_call.h"
00012 #include <boost/signals2.hpp>
00013 #include <boost/bind.hpp>
00014 #include "jml/arch/format.h"
00015 
00016 
00017 using namespace std;
00018 using namespace ML;
00019 
00020 
00021 namespace Datacratic {
00022 
00023 bool inJsContext()
00024 {
00025     return true;
00026     return v8::Locker::IsLocked();
00027 }
00028 
00029 void enterJs(void * & locker)
00030 {
00031     locker = 0;
00032     if (v8::Locker::IsLocked()) return;
00033     v8::Locker::StartPreemption(1);  // every one ms
00034     locker = new v8::Locker();
00035 }
00036 
00037 void exitJs(void * & locker_)
00038 {
00039     if (!locker_) return;
00040     v8::Locker * locker = (v8::Locker *)locker_;
00041     delete locker;
00042     locker_ = 0;
00043 }
00044 
00045 /*****************************************************************************/
00046 /* SLOT DISCONNECTOR                                                         */
00047 /*****************************************************************************/
00048 
00049 SlotDisconnector::
00050 SlotDisconnector(const boost::signals2::connection & connection)
00051     : boost::function<void (void)>
00052       (boost::bind(&boost::signals2::connection::disconnect,
00053                    connection))
00054 {
00055 }
00056 
00057 
00058 /*****************************************************************************/
00059 /* SLOT                                                                      */
00060 /*****************************************************************************/
00061 
00062 Slot::
00063 Slot(const Slot & other)
00064     : fn(other.fn), ops(other.ops), jsops(other.jsops), fntype(other.fntype)
00065 {
00066     switch (fntype) {
00067     case EMPTY: break;
00068     case BOOST:
00069         if (ops && fn)
00070             fn = (boost::function_base *)(ops(3, fn));
00071         break;
00072     case JS:
00073         jsfn = new v8::Persistent<v8::Function>
00074             (v8::Persistent<v8::Function>::New(*jsfn));
00075         break;
00076     default:
00077         throw Exception("wrong fntype");
00078     }
00079 }
00080 
00081 Slot::
00082 Slot(Slot && other)
00083     : fn(other.fn), ops(other.ops), jsops(other.jsops), fntype(other.fntype)
00084 {
00085     other.fntype = EMPTY;
00086 }
00087 
00088 Slot::
00089 Slot(const v8::Handle<v8::Function> & fn)
00090     : jsfn(new v8::Persistent<v8::Function>
00091            (v8::Persistent<v8::Function>::New(fn))),
00092       fntype(JS)
00093 {
00094     if (fn.IsEmpty() || jsfn->IsEmpty())
00095         throw Exception("invalid function");
00096 }
00097 
00098 Slot::
00099 Slot(const v8::Handle<v8::Value> & fn)
00100     : jsfn(new v8::Persistent<v8::Function>
00101            (v8::Persistent<v8::Function>::New
00102             (v8::Handle<v8::Function>
00103              (v8::Function::Cast(*fn))))),
00104       fntype(JS)
00105 {
00106     if (fn.IsEmpty())
00107         throw Exception("invalid function");
00108     if (jsfn->IsEmpty())
00109         throw Exception("Non-function JS value " + JS::cstr(fn) + " passed to slot");
00110 }
00111 
00112 Slot::
00113 ~Slot()
00114 {
00115     free();
00116 }
00117      
00118 void
00119 Slot::
00120 free()
00121 {
00122     switch (fntype) {
00123     case EMPTY: break;
00124     case BOOST:
00125         if (ops) ops(1, fn);
00126         break;
00127     case JS:
00128         if (jsfn) {
00129             jsfn->Dispose();
00130             jsfn->Clear();
00131             delete jsfn;
00132         }
00133         break;
00134     default:
00135         throw Exception("Slot::free(): wrong type");
00136     }
00137 
00138     fntype = EMPTY;
00139 }
00140 
00141 Slot &
00142 Slot::
00143 operator = (const Slot & other)
00144 {
00145     Slot new_me(other);
00146     swap(new_me);
00147     return *this;
00148 }
00149 
00150 Slot &
00151 Slot::
00152 operator = (Slot && other)
00153 {
00154     Slot new_me(other);
00155     swap(other);
00156     return *this;
00157 }
00158 
00159 void
00160 Slot::
00161 swap(Slot & other)
00162 {
00163     std::swap(fntype, other.fntype);
00164     std::swap(fn, other.fn);
00165     std::swap(ops, other.ops);
00166     std::swap(jsops, other.jsops);
00167 }
00168 
00169 std::string
00170 Slot::
00171 print() const
00172 {
00173     switch (fntype) {
00174     case EMPTY:
00175         return "(empty)";
00176     case BOOST:
00177         return "(c++) " + ML::demangle(type()) + "  as "
00178             + ML::demangle(fn->target_type());
00179     case JS:
00180         return "(js) " + JS::cstr(*jsfn);
00181     default:
00182         return "(invalid type) " + ML::format("%d", fntype);
00183     }
00184 }
00185         
00186 v8::Handle<v8::Value>
00187 Slot::
00188 call(const v8::Arguments & args) const
00189 {
00190     switch (fntype) {
00191     case EMPTY:
00192         throw Exception("cannot call an empty function");
00193     case BOOST: {
00194         if (!jsops)
00195             throw ML::Exception("no javascript translator");
00196         JS::JSCallsBoost op = (JS::JSCallsBoost)jsops;
00197 
00198         v8::HandleScope scope;
00199 
00200         v8::Handle<v8::Value> result;
00201         op(0, *fn, args, result);
00202         return scope.Close(result);
00203     }
00204     case JS: {
00205         // Forward directly to JS
00206         v8::HandleScope scope;
00207         vector<v8::Local<v8::Value> > vals(args.Length());
00208         for (unsigned i = 0;  i < vals.size();  ++i)
00209             vals[i] = args[i];
00210         return scope.Close((*jsfn)->Call(args.This(), args.Length(),
00211                                          &vals[0]));
00212     }
00213     default:
00214         throw Exception("invalid fn type");
00215     }
00216 }
00217 
00218 v8::Handle<v8::Value>
00219 Slot::
00220 call(const v8::Handle<v8::Object> & This,
00221      int argc, v8::Handle<v8::Value> argv[]) const
00222 {
00223     switch (fntype) {
00224     case EMPTY:
00225         throw Exception("cannot call an empty function");
00226     case BOOST: {
00227         if (!jsops)
00228             throw ML::Exception("no javascript translator");
00229         JS::JSCallsBoost op = (JS::JSCallsBoost)jsops;
00230 
00231         v8::HandleScope scope;
00232 
00233         v8::Handle<v8::Value> result;
00234         op(0, *fn, JS::JSArgs(This, argc, argv), result);
00235 
00236         return scope.Close(result);
00237     }
00238     case JS:
00239         // Forward directly to JS
00240         return (*jsfn)->Call(This, argc, argv);
00241     default:
00242         throw Exception("invalid fn type");
00243     }
00244 }
00245 
00246 const std::type_info &
00247 Slot::
00248 type() const
00249 {
00250     switch (fntype) {
00251     case EMPTY:
00252         return typeid(void);
00253     case BOOST: {
00254         std::type_info * p = 0;
00255         ops(0, &p);
00256         return *p;
00257     }
00258     case JS:
00259         return typeid(v8::Function);
00260     default:
00261         throw Exception("Slot::type(): invalid type");
00262     }
00263 }
00264 
00265 namespace JS {
00266 
00267 Slot from_js(const JSValue & val, Slot *)
00268 {
00269     return Slot(from_js(val, (v8::Handle<v8::Function> *)0));
00270 }
00271 
00272 } // namespace JS
00273 
00274 } // namespace Datacratic
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator