drr.cxx

Go to the documentation of this file.
00001 // @(#)root/ruby:$Id: drr.cxx 29635 2009-07-30 14:09:19Z rdm $
00002 // Author:  Elias Athanasopoulos, May 2004
00003 
00004 /*  Ruby bindings 
00005  *
00006  *  Elias Athanasopoulos  <elathan@ics.forth.gr> 
00007  *
00008  *  (c) 2003, 2004, 2006, 2007, 2008
00009 */
00010 
00011 #include "RConfigOptions.h"
00012 #include "TROOT.h"
00013 #include "TClass.h"
00014 #include "TApplication.h"
00015 #include "TSystem.h"
00016 #include "TRandom.h"
00017 #include "TF2.h"
00018 #include "TBenchmark.h"
00019 #include "TVirtualPad.h"
00020 #include "TStyle.h"
00021 
00022 #include "CallFunc.h"
00023 #include "Class.h"
00024 
00025 #include "ruby.h"
00026 
00027 #include "rrcommon.h"
00028 
00029 /* ROOT's global enums.  */
00030 #include "rrenums.h"
00031 
00032 /* Special for Unixes */
00033 #if defined(linux) || defined(sun)
00034   #include "dlfcn.h"
00035 #endif
00036 
00037 #if ((R__RUBY_MAJOR<1) || (R__RUBY_MAJOR==1)&&(R__RUBY_MINOR<=9))
00038 #  define rb_frame_this_func rb_frame_last_func
00039 #endif
00040 
00041 
00042 VALUE cTObject;
00043 
00044 VALUE rr_ary_new (TList *l)
00045 {
00046     /* convert a TList to a Ruby array */
00047     VALUE arr = rb_ary_new();
00048     VALUE o;
00049 
00050     TObject *rro;
00051     TIter next (l);
00052 
00053     while ((rro = next()))
00054       {
00055         RRNEW(o, cTObject);
00056         rb_iv_set (o, "__rr__", Data_Wrap_Struct (cTObject, 0, 0, rro));
00057         rb_iv_set (o, "__rr_class__",
00058                 rb_str_new2(rro->ClassName()));
00059         rb_ary_push (arr, o);
00060       }
00061 
00062     return arr;
00063 }
00064 
00065 static VALUE rr_to_ary (VALUE self)
00066 {
00067     /* convert a TCollection to a Ruby array */
00068     RRGRAB(self, TList, l);
00069     return rr_ary_new (l);
00070 }
00071 
00072 VALUE rr_arrayc_new (const TArrayC *a)
00073 {
00074     /* convert a TArrayC to a Ruby array */
00075     VALUE arr = rb_ary_new();
00076 
00077     for (int i = 0; i < a->GetSize(); i++)
00078         rb_ary_push (arr, INT2NUM(a->At(i)));
00079 
00080     return arr;
00081 }
00082 
00083 VALUE rr_arrays_new (const TArrayS *a)
00084 {
00085     /* convert a TArrayS to a Ruby array */
00086     VALUE arr = rb_ary_new();
00087 
00088     for (int i = 0; i < a->GetSize(); i++)
00089         rb_ary_push (arr, INT2NUM(a->At(i)));
00090 
00091     return arr;
00092 }
00093 
00094 VALUE rr_arrayi_new (const TArrayI *a)
00095 {
00096     /* convert a TArrayI to a Ruby array */
00097     VALUE arr = rb_ary_new();
00098 
00099     for (int i = 0; i < a->GetSize(); i++)
00100         rb_ary_push (arr, INT2NUM(a->At(i)));
00101 
00102     return arr;
00103 }
00104 
00105 VALUE rr_arrayl_new (const TArrayL *a)
00106 {
00107     /* convert a TArrayL to a Ruby array */
00108     VALUE arr = rb_ary_new();
00109 
00110     for (int i = 0; i < a->GetSize(); i++)
00111         rb_ary_push (arr, INT2NUM(a->At(i)));
00112 
00113     return arr;
00114 }
00115 
00116 VALUE rr_arrayf_new (const TArrayF *a)
00117 {
00118     /* convert a TArrayC to a Ruby array */
00119     VALUE arr = rb_ary_new();
00120 
00121     for (int i = 0; i < a->GetSize(); i++)
00122         rb_ary_push (arr, rb_float_new(a->At(i)));
00123 
00124     return arr;
00125 }
00126 
00127 VALUE rr_arrayd_new (const TArrayD *a)
00128 {
00129     /* convert a TArrayD to a Ruby array */
00130     VALUE arr = rb_ary_new();
00131 
00132     for (int i = 0; i < a->GetSize(); i++)
00133         rb_ary_push (arr, rb_float_new(a->At(i)));
00134 
00135     return arr;
00136 }
00137 
00138 VALUE rr_seqcollection_new (TSeqCollection *sc)
00139 {
00140     /* convert a TSeqCollection to a Ruby Array */
00141     VALUE arr = rb_ary_new();
00142     VALUE o;
00143 
00144     for (int i = 0; i < sc->GetSize(); i++)
00145       {
00146         RRNEW(o, cTObject);
00147         rb_iv_set (o, "__rr__", Data_Wrap_Struct (cTObject, 0, 0, sc->At(i)));
00148         rb_ary_push (arr, o);
00149       }
00150 
00151     return arr;
00152 }
00153 
00154 void * rr_parse_void (VALUE o)
00155 {
00156     VALUE *i;
00157 
00158     switch (TYPE(o))
00159       {
00160         case T_STRING:
00161             return (void *) RSTRING(o)->ptr;
00162         case T_FLOAT:
00163             return (void *) &RFLOAT(o)->value;
00164         case T_FIXNUM:
00165             /* FIXME: Memory leak until I find the correct way. Until
00166              * then please use integers in TTrees with care. --elathan
00167              */
00168             i = (VALUE*) malloc (sizeof(int));
00169             *i = (int) (o>>1);
00170             return (void *) i;
00171         case T_OBJECT:
00172             RRGRAB(o, void *, res);
00173             return res;
00174         default:
00175             rb_fatal ("Failed convertion of %d to void *.\n",
00176                       STR2CSTR(CLASS_OF(o)));
00177             break;
00178       }
00179 
00180     return (void *) NULL;
00181 }
00182 
00183 VALUE rr_bool (bool q)
00184 {
00185     VALUE res = Qnil;
00186 
00187     q == 0 ? res = Qfalse : res = Qtrue;
00188 
00189     return res;
00190 }
00191 
00192 /* Wrappers for function pointers.  */
00193 
00194 /* TF1 */
00195 static struct rr_fcn_info * rr_tf1_table[256];
00196 static int rr_tf1_tblptr = 0;
00197 
00198 double rr_ctf1_fcn (double *x, double* par)
00199 {
00200     TF1 *fcn = (TF1 *)TF1::GetCurrent();
00201     struct rr_fcn_info *info = NULL;
00202 
00203     for (int i = 0; i < rr_tf1_tblptr; i++)
00204       {
00205         info = rr_tf1_table[i];
00206         if (!strcmp(info->name, fcn->GetName()))
00207             break;
00208         else
00209             info = NULL;
00210       }
00211 
00212     if (info == NULL)
00213     rb_warn("Ruby user defined function has not been registered for %s (%p).",
00214         fcn->GetName(), fcn);
00215 
00216     int n = fcn->GetNpar();
00217     VALUE vx = rb_ary_new2 (n);
00218     VALUE vpar = rb_ary_new2 (n);
00219     for (int i = 0; i < n; i++)
00220       {
00221         rb_ary_push (vx, rb_float_new(x[i]));
00222         rb_ary_push (vpar, rb_float_new(par[i]));
00223       }
00224 
00225     double res = NUM2DBL(rb_funcall (rb_cObject, info->id, 2, vx, vpar));
00226     return res;
00227 }
00228 
00229 void rr_register_ctf1_fcn (char *name, ID id)
00230 {
00231     struct rr_fcn_info *info = (struct rr_fcn_info *)malloc (sizeof *info);
00232 
00233     info->name = strdup(name);
00234     info->id = id;
00235 
00236     rr_tf1_table[rr_tf1_tblptr] = info;
00237     rr_tf1_tblptr++;
00238 
00239 }
00240 
00241 static struct rr_fcn_info * rr_tf2_table[256];
00242 static int rr_tf2_tblptr = 0;
00243 
00244 double rr_ctf2_fcn (double *x, double* par)
00245 {
00246     TF2 *fcn = (TF2 *)TF2::GetCurrent();
00247     struct rr_fcn_info *info = NULL;
00248 
00249     for (int i = 0; i < rr_tf2_tblptr; i++)
00250       {
00251         info = rr_tf2_table[i];
00252         if (!strcmp(info->name, fcn->GetName()))
00253             break;
00254         else
00255             info = NULL;
00256       }
00257 
00258     if (info == NULL)
00259     rb_warn("Ruby user defined function has not been registered for %s (%p).",
00260         fcn->GetName(), fcn);
00261 
00262     int n = fcn->GetNpar();
00263     VALUE vx = rb_ary_new2 (n);
00264     VALUE vpar = rb_ary_new2 (n);
00265     for (int i = 0; i < n; i++)
00266       {
00267         rb_ary_push (vx, rb_float_new(x[i]));
00268         rb_ary_push (vpar, rb_float_new(par[i]));
00269       }
00270 
00271     double res = NUM2DBL(rb_funcall (rb_cObject, info->id, 2, vx, vpar));
00272     return res;
00273 }
00274 
00275 void rr_register_ctf2_fcn (char *name, ID id)
00276 {
00277     struct rr_fcn_info *info = (struct rr_fcn_info *)malloc (sizeof *info);
00278 
00279     info->name = strdup(name);
00280     info->id = id;
00281 
00282     rr_tf2_table[rr_tf2_tblptr] = info;
00283     rr_tf2_tblptr++;
00284 
00285 }
00286 /* Implementation */
00287 
00288 /* Globals */
00289 
00290 static VALUE rr_gsystem (void)
00291 {
00292     VALUE o;
00293 
00294     RRNEW(o, cTObject);
00295     rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gSystem));
00296     rb_iv_set (o, "__rr_class__", rb_str_new2("TSystem"));
00297 
00298     return o;
00299 }
00300 
00301 static VALUE rr_grandom (void)
00302 {
00303     VALUE o;
00304 
00305     RRNEW(o, cTObject);
00306     rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gRandom));
00307     rb_iv_set (o, "__rr_class__", rb_str_new2("TRandom"));
00308 
00309     return o;
00310 }
00311 
00312 static VALUE rr_gbenchmark (void)
00313 {
00314     VALUE o;
00315 
00316     RRNEW(o, cTObject);
00317     rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gBenchmark));
00318     rb_iv_set (o, "__rr_class__", rb_str_new2("TBenchmark"));
00319 
00320     return o;
00321 }
00322 
00323 static VALUE rr_gpad (void)
00324 {
00325     VALUE o;
00326 
00327     RRNEW(o, cTObject);
00328     rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gPad));
00329     rb_iv_set (o, "__rr_class__", rb_str_new2("TPad"));
00330 
00331     return o;
00332 }
00333 
00334 static VALUE rr_gstyle (void)
00335 {
00336     VALUE o;
00337 
00338     RRNEW(o, cTObject);
00339     rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gStyle));
00340     rb_iv_set (o, "__rr_class__", rb_str_new2("TStyle"));
00341 
00342     return o;
00343 }
00344 
00345 static VALUE rr_gdirectory (void)
00346 {
00347     VALUE o;
00348 
00349     RRNEW(o, cTObject);
00350     rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gDirectory));
00351     rb_iv_set (o, "__rr_class__", rb_str_new2("TDirectory"));
00352 
00353     return o;
00354 }
00355 
00356 static VALUE rr_groot (void)
00357 {
00358     VALUE o;
00359 
00360     RRNEW(o, cTObject);
00361 
00362     rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gROOT));
00363     rb_iv_set (o, "__rr_class__", rb_str_new2("TROOT"));
00364 
00365     return o;
00366 }
00367 
00368 static VALUE rr_gapplication (void)
00369 {
00370     VALUE o;
00371 
00372     RRNEW(o, cTObject);
00373 
00374     rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gApplication));
00375     rb_iv_set (o, "__rr_class__", rb_str_new2("TApplication"));
00376 
00377     return o;
00378 }
00379 
00380 static VALUE via (VALUE self, VALUE ameth, VALUE bmeth, VALUE parms)
00381 {
00382     if (TYPE(ameth) != T_SYMBOL &&
00383         TYPE(bmeth) != T_SYMBOL &&
00384         TYPE(parms) != T_HASH)
00385       {
00386         rb_fatal ("rr-via: Please call TObject#via with sym, sym, hash.");
00387         return Qnil;
00388       }
00389 
00390     VALUE keys = rb_funcall(parms, rb_intern("keys"), 0);
00391     for (int i = 0; i < RARRAY(keys)->len; i++)
00392       {
00393         VALUE key = rb_ary_entry (keys, i);
00394         rb_funcall (self, rb_to_id (ameth), 2, key, rb_hash_aref (parms, key));
00395       }
00396     rb_funcall(self, rb_to_id(bmeth), 0);
00397 
00398     return self;
00399 }
00400 
00401 /* Dynamic ruby-root specific implementation.  */
00402 
00403 TObject* drr_grab_object(VALUE self)
00404 {
00405     static TObject *o;
00406     Data_Get_Struct(rb_iv_get (self, "__rr__"), TObject, o);
00407     return o;
00408 }
00409 
00410 unsigned int drr_map_args2(VALUE inargs, char *cproto, G__CallFunc *f, long int offset=1, unsigned int reference_map=0x0)
00411 {
00412     /* FIXME. Offset reminds me fortran code; make a better interface,
00413      * and change the function name to a better one.
00414      *
00415      * The boolean checks for cproto and f are vital. This function can
00416      * be called:
00417      *
00418      * 1. When we want a C prototype from a Ruby call
00419      * 2. When we want to set the arguments of a CINT function
00420      * 3. When we want both 1 and 2
00421      */
00422 
00423     int nargs = RARRAY(inargs)->len - offset;
00424     double *arr = NULL;
00425     TObject *ptr = NULL;
00426     VALUE v = 0;
00427 
00428     unsigned int ntobjects = 0;
00429 
00430     /* Transform Ruby arguments to C/C++.  */
00431     for (int i = 0; i < nargs; i++)
00432       {
00433         VALUE arg = rb_ary_entry (inargs, i+offset);
00434         switch (TYPE(arg))
00435           {
00436             case T_FIXNUM:
00437                 if (f) f->SetArg((long) NUM2INT(arg));
00438                 if (cproto) strcat(cproto, "int");
00439                 break;
00440             case T_FLOAT:
00441                 if (f) f->SetArg(NUM2DBL(arg));
00442                 if (cproto) strcat(cproto, "double");
00443                 break;
00444             case T_STRING:
00445                 if (f) f->SetArg((long) STR2CSTR(arg));
00446                 if (cproto) strcat(cproto, "char*");
00447                 break;
00448             case T_ARRAY:
00449                 /* FIXME: Handle all arrays, not only
00450                  * with floats.
00451                  */
00452                 if (f)
00453                   {
00454                     arr = ALLOC_N (double, RARRAY(arg)->len);
00455                     for (int j = 0; j < RARRAY(arg)->len; j++)
00456                         arr[j] = NUM2DBL(rb_ary_entry (arg, j));
00457                     f->SetArg((long) arr);
00458                   }
00459                 if (cproto) strcat(cproto, "double*");
00460                 break;
00461             case T_OBJECT:
00462                 v = rb_iv_get (arg, "__rr__");
00463                 if (!NIL_P(v))
00464                   {
00465                     Data_Get_Struct (v, TObject, ptr);
00466                     if (f) f->SetArg((long) ptr);
00467                     if (cproto) {
00468                         strcat(cproto, STR2CSTR(rb_iv_get (arg, "__rr_class__")));
00469                         if( ((reference_map>>ntobjects)&0x1) ) {
00470                           strcat(cproto, "*");
00471                         } else {
00472                           strcat(cproto, "&");
00473                         }
00474                     }
00475                   }
00476                 ++ntobjects;
00477                 break;
00478             default:
00479                 break;
00480           }
00481         if ((i + 1 < nargs) && (nargs != 1) && cproto) 
00482             strcat(cproto, ",");
00483       }
00484     return ntobjects;
00485 }
00486 
00487 void drr_find_method_prototype( G__ClassInfo *klass, char *methname, VALUE inargs, char *cproto, long int offset=1 )
00488 {
00489     /* FIXME: Brute force checking of all combinations of * and & for
00490      * T_Objects Since we cannot tell which one is needed (we get the type
00491      * from the ruby objects, which don't know) we try all.
00492      */
00493 
00494     G__MethodInfo *minfo = 0;
00495     long int dummy_offset = 0; // Not read out, but expected by GetMethod
00496 
00497     // Number of T_OBJECTS in argument list initialized to more than 1
00498     unsigned int nobjects = drr_map_args2 (inargs, cproto, 0, offset, 0x0);
00499     // 2^nobjects == number of combinations of "*" and "&"
00500     unsigned int bitmap_end = static_cast<unsigned int>( 0x1 << nobjects );
00501 
00502     // Check if method methname with prototype cproto is present in klass
00503     minfo = new G__MethodInfo(klass->GetMethod(methname, cproto, &dummy_offset));
00504 
00505     /* Loop if we have to, i.e. there are T_OBJECTS ^= TObjects and the first
00506      * combination is not correct.
00507      */
00508     if( nobjects > 0 and !(minfo->InterfaceMethod()) ) {
00509         for( unsigned int reference_map=0x1; reference_map < bitmap_end; reference_map++) {
00510             cproto[0] = static_cast<char>( 0 ); // reset cproto
00511             drr_map_args2 (inargs, cproto, 0, offset, reference_map);
00512             minfo = new G__MethodInfo(klass->GetMethod(methname, cproto, &dummy_offset));
00513             if (minfo->InterfaceMethod())
00514                 break;
00515         }
00516     } 
00517 
00518     delete minfo;
00519 
00520     return;
00521 }
00522 
00523 void drr_set_method_args( VALUE inargs, G__CallFunc *func, long int offset=1 )
00524 {
00525     drr_map_args2( inargs, 0, func, offset );
00526 }
00527 
00528 enum ktype {kint, kfloat, kchar, kunknown, kvoid, kintary, kfloatary, kstring, kroot, kbool};
00529 
00530 int drr_parse_ret_type (const char *ret)
00531 {
00532     char *realtype = strdup(ret), *t = realtype;
00533     int plevel = 0;
00534         enum ktype type;
00535 
00536     while (*(t++)) {
00537         if (*t == '*')
00538             plevel++;
00539     }
00540 
00541     t--;
00542 
00543     if (plevel > 0)
00544         *(t - plevel) = '\0';
00545 
00546     if (!strncmp(t - 3, "int", 3) ||
00547         !strncmp(t - 4, "long", 4))
00548         type = kint;
00549     else
00550     if (!strncmp(t - 6, "double", 6) ||
00551         !strncmp(t - 5, "float", 5))
00552         type = kfloat;
00553     else
00554     if (!strncmp(t - 5, "char", 4))
00555         type = kchar;
00556     else
00557     if (!strncmp(t - 4, "void", 4))
00558         type = kvoid;
00559     else
00560     if (!strncmp(t - 4, "bool", 4))
00561         type = kbool;
00562     else
00563         type = kunknown;
00564 
00565     if (plevel)
00566                 /* Quick hack to move from ordinary types to pointer types,
00567                  * which are essntially arrays of values. For example an integer
00568                  * (kint) is transformed to an array of integers (kintary).  */
00569         type = (enum ktype)(type + 5);
00570 
00571     free (realtype);
00572 
00573     return type;
00574 }
00575 
00576 /* Function cache related.  */
00577 
00578 struct drr_func_cache * drr_func_cache_init(struct drr_func_entry *entry)
00579 {
00580     struct drr_func_cache *new_cache = (struct drr_func_cache *) malloc (sizeof *new_cache);
00581     new_cache->next = NULL;
00582     new_cache->entry = entry;
00583     new_cache->last = NULL;
00584     return new_cache;
00585 }
00586 
00587 void drr_func_cache_push (struct drr_func_cache *cache, struct drr_func_entry *entry)
00588 {
00589     struct drr_func_cache *n = (struct drr_func_cache *) malloc(sizeof *n);
00590     n->entry = entry;
00591 
00592     if (cache->next)
00593       {
00594         n->next = cache->next;
00595         cache->next = n;
00596       }
00597     else
00598       {
00599         cache->next = n;
00600         n->next = NULL;
00601       }
00602 }
00603 
00604 struct drr_func_entry * drr_func_cache_find (struct drr_func_cache *cache, char *name)
00605 {
00606     struct drr_func_cache *iter = cache;
00607 
00608     while (iter)
00609       {
00610         if (!strcmp (iter->entry->name, name))
00611             return iter->entry;
00612         iter = iter->next;
00613       }
00614     return NULL;
00615 }
00616 
00617 void drr_func_entry_free (struct drr_func_entry *entry)
00618 {
00619     delete entry->func;
00620     delete entry->klass;
00621     free (entry->name);
00622     free (entry->cproto);
00623     free (entry);
00624 }
00625 
00626 /* Ruby generic interface.  */
00627 
00628 VALUE drrAbstractClass;
00629 
00630 static VALUE drr_as(VALUE self, VALUE klass)
00631 {
00632     /* Pseudo C++ casting.  */
00633     VALUE v;
00634 
00635     /* Check if there is a ROOT dict. available.  */
00636     TClass *c = TClass::GetClass(STR2CSTR(klass));
00637     if (c)
00638       {
00639         VALUE k;
00640         char *name = STR2CSTR(klass);
00641         if (!rb_const_defined (rb_cObject, rb_intern(name)))
00642             k = rb_define_class (name, drrAbstractClass);
00643         else
00644             k = rb_path2class (name);
00645 
00646         RRNEW(v, k);
00647         rb_iv_set (v, "__rr__", rb_iv_get(self, "__rr__"));
00648         rb_iv_set (v, "__rr_class__", klass);
00649       }
00650     else
00651         rb_raise( rb_eArgError, "No TClass found for %s. Is this a Root type?", STR2CSTR(klass) );
00652 
00653     return v;
00654 }
00655 
00656 static VALUE drr_init(int argc, VALUE argv[], VALUE self)
00657 {
00658     VALUE inargs;
00659     char *classname = (char*) rb_obj_classname(self);
00660     char cproto[1024] = "";
00661     long addr = 0, offset;
00662 
00663     rb_scan_args (argc, argv, "0*", &inargs);
00664 
00665     G__CallFunc func;
00666     G__ClassInfo klass(classname);
00667 
00668     /* Call the requested ctor.  */
00669 
00670     if (RARRAY(inargs)->len) {
00671         drr_find_method_prototype (&klass, classname, inargs, cproto, 0);
00672         drr_set_method_args ( inargs, &func, 0);
00673     }
00674 
00675     G__MethodInfo minfo(klass.GetMethod(classname, cproto, &offset));
00676     if (minfo.InterfaceMethod())
00677         func.SetFunc(minfo);
00678     else
00679         rb_raise( rb_eArgError, "You provided an unknown prototype (%s) for (%s#%s).",
00680                     cproto, classname, classname);
00681 
00682     addr = func.ExecInt((void*)((long)0 + offset));
00683     rb_iv_set(self, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, (TObject *)addr));
00684     rb_iv_set(self, "__rr_class__", rb_str_new2 (classname));
00685 
00686     func.Init();
00687     return self;
00688 }
00689 
00690 static VALUE drr_return(int rtype, long value_address, double dvalue_address, VALUE self)
00691 {
00692         VALUE vret;
00693 
00694         switch (rtype)
00695       {
00696         case kint:
00697             vret = INT2NUM(value_address);
00698             break;
00699         case kfloat:
00700             vret = rb_float_new(dvalue_address);
00701             break;
00702         case kstring:
00703             vret = rb_str_new2((char *)value_address);
00704             break;
00705         case kbool:
00706             vret = rr_bool((bool)value_address);
00707             break;
00708         case kroot:
00709             if (!value_address)
00710         return Qnil;
00711 
00712             if (!strcmp(((TObject*)(value_address))->ClassName(), "TList"))
00713                 vret = rr_ary_new((TList*)value_address);
00714                         else
00715               {
00716                 VALUE res;
00717                 RRNEW(res, cTObject);
00718                 rb_iv_set(res, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, (TObject*)value_address));
00719                 rb_iv_set(res, "__rr_class__", rb_str_new2 (((TObject*)(value_address))->ClassName()));
00720                 vret = res;
00721               }
00722 
00723             break;
00724 
00725         default:
00726             vret = self;
00727             break;
00728       }
00729 
00730         return vret;
00731 }
00732 
00733 
00734 static VALUE drr_const_missing(VALUE self, VALUE klass)
00735 {
00736     /* Define a new ROOT Class dynammically.  */
00737 
00738     char *name = (char*) rb_id2name (rb_to_id(klass));
00739 
00740     /* Check if there is a ROOT dict. available.  */
00741     TClass *c = new TClass(name);
00742     if (c && c->GetClassInfo()) {
00743         VALUE new_klass = rb_define_class (name, drrAbstractClass);
00744         delete c;
00745         return new_klass;
00746     } else {
00747         delete c;
00748         /* If there is no ROOT dict available, call the original Object::const_missing */
00749         return rb_funcall(self,rb_intern("__drr_orig_const_missing"),1,klass);
00750     }
00751 }
00752 
00753 static VALUE drr_singleton_missing(int argc, VALUE argv[], VALUE self)
00754 {
00755         VALUE inargs;
00756         char cproto[1024] = "";
00757     int nargs;
00758         long offset, address = 0;
00759     double dbladdr = 0;
00760 
00761     /* Call a singleton method.  */
00762         char * methname = (char*) rb_id2name (rb_to_id(argv[0]));
00763     char * classname = (char *) rb_class2name(self);
00764         
00765         rb_scan_args (argc, argv, "0*", &inargs);
00766     nargs = RARRAY(inargs)->len - 1;
00767 
00768         G__CallFunc *func = new G__CallFunc();
00769     G__ClassInfo *klass = new G__ClassInfo (classname);
00770     G__MethodInfo *minfo = 0;
00771 
00772         if (nargs) {
00773         drr_find_method_prototype( klass, methname, inargs, cproto, 1 );
00774         drr_set_method_args( inargs, func, 1 );
00775     }
00776 
00777         /* FIXME: minfo is really used only for the return type.  */
00778     minfo = new G__MethodInfo(klass->GetMethod(methname, cproto, &offset));
00779     if (minfo->InterfaceMethod())
00780         func->SetFunc(*minfo);
00781     else
00782         rb_raise( rb_eArgError, "You provided an unknown prototype (%s) for (%s#%s).",
00783                     cproto, classname, methname);
00784 
00785         delete minfo;
00786 
00787         int rtype = drr_parse_ret_type (minfo->Type()->TrueName());
00788 
00789     if (rtype != kfloat)
00790         address = func->ExecInt((void*)(offset));
00791     else
00792         dbladdr = func->ExecDouble((void*)(offset));
00793 
00794         return(drr_return(rtype, address, dbladdr, self));
00795 }
00796 
00797 
00798 static VALUE drr_method_missing(int argc, VALUE argv[], VALUE self)
00799 {
00800     /* When a ROOT method is called, we try to resolve it here. If
00801      * CINT is able to resolve it then we define a Ruby method using
00802      * a similar generic function (drr_generic_method), so as
00803      * Ruby not to use the Object#method_missing every time.
00804      */
00805 
00806     VALUE inargs;
00807     char *methname, *classname ;
00808     long offset, address = 0;
00809     double dbladdr = 0;
00810     char cproto[1024] = "";
00811     int nargs;
00812 
00813     /* Grab method, class and the instance pointer.  */
00814     methname = (char*) rb_id2name (rb_to_id(argv[0]));
00815     classname = STR2CSTR(rb_iv_get (self, "__rr_class__"));
00816     TObject *caller = drr_grab_object (self);
00817 
00818     rb_scan_args (argc, argv, "0*", &inargs);
00819 
00820     nargs = RARRAY(inargs)->len - 1;
00821     VALUE rklass = rb_class_of (self);
00822 
00823     G__CallFunc *func = new G__CallFunc();
00824     G__ClassInfo *klass = new G__ClassInfo (classname);
00825     G__MethodInfo *minfo = 0;
00826 
00827     if (nargs) {
00828         drr_find_method_prototype( klass, methname, inargs, cproto, 1 );
00829         drr_set_method_args( inargs, func, 1 );
00830     }
00831 
00832     /* FIXME: minfo is really used only for the return type.  */
00833     minfo = new G__MethodInfo(klass->GetMethod(methname, cproto, &offset));
00834     if (minfo->InterfaceMethod())
00835         func->SetFunc(*minfo);
00836     else
00837         rb_raise( rb_eArgError, "You provided an unknown prototype (%s) for (%s#%s).",
00838                     cproto, classname, methname);
00839 
00840     /* This is the first time this method is called. Create a cash entry.  */
00841     struct drr_func_entry *entry = (struct drr_func_entry *) malloc (sizeof *entry);
00842     entry->func = func;
00843     entry->klass = klass;
00844     entry->name = strdup(methname);
00845     entry->cproto = strdup(cproto);
00846     entry->rtype = drr_parse_ret_type (minfo->Type()->TrueName());
00847 
00848     delete minfo;
00849 
00850     struct drr_func_cache *cache;
00851     /* If there is no cache available, create one (per Class scope).  */
00852     if (!rb_cvar_defined (rklass, rb_intern("@@__func_table__")))
00853         cache = drr_func_cache_init (entry);
00854     else
00855         Data_Get_Struct(rb_cv_get(rklass, "@@__func_table__"), struct drr_func_cache, cache);
00856 
00857     /* Push the method to the cache and save it back to the Class.  */
00858     drr_func_cache_push (cache, entry);
00859     rb_cv_set (rklass, "@@__func_table__",
00860         Data_Wrap_Struct(cTObject, 0, 0, cache));
00861 
00862     if (entry->rtype != kfloat)
00863         address = func->ExecInt((void*)((long)caller + offset));
00864     else
00865         dbladdr = func->ExecDouble((void*)((long)caller + offset));
00866 
00867     /* Define method.  */
00868     rb_define_method (rklass, methname, VALUEFUNC(drr_generic_method), -1);
00869 
00870         return(drr_return(entry->rtype, address, dbladdr, self));
00871 }
00872 
00873 static VALUE drr_generic_method(int argc, VALUE argv[], VALUE self)
00874 {
00875     VALUE inargs;
00876     VALUE rklass;
00877     int nargs;
00878     long offset = 0, address = 0;
00879     double dbladdr = 0;
00880     char cproto[1024] = "";
00881 
00882     /* Grab class, method name and instance pointer.  */
00883     rklass = rb_class_of (self);
00884     char *methname = (char*) rb_id2name (rb_frame_this_func());
00885     TObject *caller = drr_grab_object (self);
00886 
00887     rb_scan_args (argc, argv, "0*", &inargs);
00888 
00889     nargs = RARRAY(inargs)->len;
00890 
00891     G__CallFunc *func = NULL;
00892 
00893     struct drr_func_cache *cache;
00894     struct drr_func_entry *entry;
00895 
00896     Data_Get_Struct (rb_cv_get(rklass, "@@__func_table__"), struct drr_func_cache, cache);
00897     entry = drr_func_cache_find (cache, methname);
00898 
00899     if (entry)
00900       {
00901         func = entry->func;
00902         if (nargs)
00903             drr_find_method_prototype (entry->klass, methname, inargs, cproto, 0);
00904         func->SetFuncProto (entry->klass, methname, cproto, &offset);
00905         /* FIXME: Why on earth CINT resets the arguments when
00906          * SetFuncProto() is called?
00907          */
00908         if (nargs)
00909             drr_set_method_args (inargs, func, 0);
00910       }
00911     else
00912         /* FIXME: This can never be happened.  */
00913         rb_warn ("Proto conflict with cache. Expected %s, but found: %s", cproto, entry->cproto);
00914 
00915     if (entry->rtype != kfloat)
00916         address = func->ExecInt((void*)((long)caller + offset));
00917     else
00918         dbladdr = func->ExecDouble((void*)((long)caller + offset));
00919 
00920         return(drr_return(entry->rtype, address, dbladdr, self));
00921 }
00922 
00923 extern "C"
00924 void Init_libRuby() {
00925 
00926     /* In order to have the most frequently used dictionaries
00927      * loaded by default. THIS MUST BE REPLACED BY PORTABLE CODE  */
00928 #if defined(linux) || defined(sun)
00929    dlopen( "libCint.so",   RTLD_GLOBAL | RTLD_LAZY );
00930    dlopen( "libCore.so",   RTLD_GLOBAL | RTLD_LAZY );
00931    dlopen( "libGpad.so",   RTLD_GLOBAL | RTLD_LAZY );
00932    dlopen( "libGraf.so",   RTLD_GLOBAL | RTLD_LAZY );
00933    dlopen( "libMatrix.so", RTLD_GLOBAL | RTLD_LAZY );
00934    dlopen( "libHist.so",   RTLD_GLOBAL | RTLD_LAZY );
00935    dlopen( "libTree.so",   RTLD_GLOBAL | RTLD_LAZY );
00936    dlopen( "libGraf3d.so", RTLD_GLOBAL | RTLD_LAZY );
00937    dlopen( "libGeom.so",   RTLD_GLOBAL | RTLD_LAZY );
00938 #endif
00939 
00940     /* Create a new ROOT Application if it doesn't already exist.  */
00941     if (!gApplication)
00942         gApplication = new TApplication("ruby root app", NULL, NULL);
00943 
00944     drrAbstractClass = rb_define_class("DRRAbstractClass", rb_cObject);
00945     rb_define_method(drrAbstractClass, "initialize", VALUEFUNC(drr_init), -1);
00946     rb_define_method(drrAbstractClass, "method_missing", VALUEFUNC(drr_method_missing), -1);
00947     rb_define_method (drrAbstractClass, "as", VALUEFUNC(drr_as), 1);
00948     /* For singleton function calls.  */
00949     rb_define_singleton_method (drrAbstractClass, "method_missing", VALUEFUNC(drr_singleton_missing), -1);
00950 
00951     cTObject = rb_define_class("TObject", drrAbstractClass);
00952 
00953     rb_define_method (cTObject, "to_ary", VALUEFUNC(rr_to_ary), 0);
00954     rb_define_method (rb_cObject, "via", VALUEFUNC(via), 3);
00955 
00956     /* Save the original Object::const_missing before overriding it
00957        Object::__drr_orig_const_missing will be called if Cint is unable to resolve the class name */
00958     rb_eval_string("Object.instance_eval { alias __drr_orig_const_missing const_missing }");
00959     rb_define_singleton_method (rb_cObject, "const_missing", VALUEFUNC(drr_const_missing), 1);
00960 
00961     /* usefull globals */
00962     rb_define_method (rb_cObject, "gSystem", VALUEFUNC(rr_gsystem), 0);
00963     rb_define_method (rb_cObject, "gRandom", VALUEFUNC(rr_grandom), 0);
00964     rb_define_method (rb_cObject, "gBenchmark", VALUEFUNC(rr_gbenchmark), 0);
00965     rb_define_method (rb_cObject, "gPad", VALUEFUNC(rr_gpad), 0);
00966     rb_define_method (rb_cObject, "gStyle", VALUEFUNC(rr_gstyle), 0);
00967     rb_define_method (rb_cObject, "gDirectory", VALUEFUNC(rr_gdirectory), 0);
00968     rb_define_method (rb_cObject, "gROOT", VALUEFUNC(rr_groot), 0);
00969     rb_define_method (rb_cObject, "gApplication", VALUEFUNC(rr_gapplication), 0);
00970 
00971     /* enums */
00972     init_global_enums();
00973 }

Generated on Tue Jul 5 14:10:17 2011 for ROOT_528-00b_version by  doxygen 1.5.1