ROOT  6.06/09
Reference Guide
drr.cxx
Go to the documentation of this file.
1 // @(#)root/ruby:$Id$
2 // Author: Elias Athanasopoulos, May 2004
3 
4 /* Ruby bindings
5  *
6  * Elias Athanasopoulos <elathan@ics.forth.gr>
7  *
8  * (c) 2003, 2004, 2006, 2007, 2008
9  */
10 
11 #include "RConfigOptions.h"
12 #include "TROOT.h"
13 #include "TClass.h"
14 #include "TApplication.h"
15 #include "TSystem.h"
16 #include "TRandom.h"
17 #include "TF2.h"
18 #include "TBenchmark.h"
19 #include "TVirtualPad.h"
20 #include "TStyle.h"
21 
22 #include "CallFunc.h"
23 #include "Class.h"
24 #include "strlcpy.h"
25 
26 #include "ruby.h"
27 
28 // Define macros for old ruby versions
29 #ifndef RSTRING_PTR
30 #define RSTRING_PTR(s) (RSTRING(s)->ptr)
31 #endif
32 #ifndef RFLOAT_VALUE
33 #define RFLOAT_VALUE(v) (RFLOAT(v)->value)
34 #endif
35 #ifndef RARRAY_LEN
36 #define RARRAY_LEN(s) (RARRAY(s)->len)
37 #endif
38 
39 #include "rrcommon.h"
40 
41 /* ROOT's global enums. */
42 #include "rrenums.h"
43 
44 /* Special for Unixes */
45 #if defined(linux) || defined(sun)
46 #include "dlfcn.h"
47 #endif
48 
49 #if ((R__RUBY_MAJOR<1) || (R__RUBY_MAJOR==1)&&(R__RUBY_MINOR<=8))
50 # define rb_frame_this_func rb_frame_last_func
51 #endif
52 
53 
54 VALUE cTObject;
55 
56 VALUE rr_ary_new (TList *l)
57 {
58  /* convert a TList to a Ruby array */
59  VALUE arr = rb_ary_new();
60  VALUE o;
61 
62  TObject *rro;
63  TIter next (l);
64 
65  while ((rro = next()))
66  {
67  RRNEW(o, cTObject);
68  rb_iv_set (o, "__rr__", Data_Wrap_Struct (cTObject, 0, 0, rro));
69  rb_iv_set (o, "__rr_class__",
70  rb_str_new2(rro->ClassName()));
71  rb_ary_push (arr, o);
72  }
73 
74  return arr;
75 }
76 
77 static VALUE rr_to_ary (VALUE self)
78 {
79  /* convert a TCollection to a Ruby array */
80  RRGRAB(self, TList, l);
81  return rr_ary_new (l);
82 }
83 
84 VALUE rr_arrayc_new (const TArrayC *a)
85 {
86  /* convert a TArrayC to a Ruby array */
87  VALUE arr = rb_ary_new();
88 
89  for (int i = 0; i < a->GetSize(); i++)
90  rb_ary_push (arr, INT2NUM(a->At(i)));
91 
92  return arr;
93 }
94 
95 VALUE rr_arrays_new (const TArrayS *a)
96 {
97  /* convert a TArrayS to a Ruby array */
98  VALUE arr = rb_ary_new();
99 
100  for (int i = 0; i < a->GetSize(); i++)
101  rb_ary_push (arr, INT2NUM(a->At(i)));
102 
103  return arr;
104 }
105 
106 VALUE rr_arrayi_new (const TArrayI *a)
107 {
108  /* convert a TArrayI to a Ruby array */
109  VALUE arr = rb_ary_new();
110 
111  for (int i = 0; i < a->GetSize(); i++)
112  rb_ary_push (arr, INT2NUM(a->At(i)));
113 
114  return arr;
115 }
116 
117 VALUE rr_arrayl_new (const TArrayL *a)
118 {
119  /* convert a TArrayL to a Ruby array */
120  VALUE arr = rb_ary_new();
121 
122  for (int i = 0; i < a->GetSize(); i++)
123  rb_ary_push (arr, INT2NUM(a->At(i)));
124 
125  return arr;
126 }
127 
128 VALUE rr_arrayf_new (const TArrayF *a)
129 {
130  /* convert a TArrayC to a Ruby array */
131  VALUE arr = rb_ary_new();
132 
133  for (int i = 0; i < a->GetSize(); i++)
134  rb_ary_push (arr, rb_float_new(a->At(i)));
135 
136  return arr;
137 }
138 
139 VALUE rr_arrayd_new (const TArrayD *a)
140 {
141  /* convert a TArrayD to a Ruby array */
142  VALUE arr = rb_ary_new();
143 
144  for (int i = 0; i < a->GetSize(); i++)
145  rb_ary_push (arr, rb_float_new(a->At(i)));
146 
147  return arr;
148 }
149 
151 {
152  /* convert a TSeqCollection to a Ruby Array */
153  VALUE arr = rb_ary_new();
154  VALUE o;
155 
156  for (int i = 0; i < sc->GetSize(); i++)
157  {
158  RRNEW(o, cTObject);
159  rb_iv_set (o, "__rr__", Data_Wrap_Struct (cTObject, 0, 0, sc->At(i)));
160  rb_ary_push (arr, o);
161  }
162 
163  return arr;
164 }
165 
166 VALUE rr_bool (Bool_t q)
167 {
168  VALUE res = Qnil;
169 
170  q == 0 ? res = Qfalse : res = Qtrue;
171 
172  return res;
173 }
174 
175 /* Wrappers for function pointers. */
176 
177 /* TF1 */
178 static struct rr_fcn_info * rr_tf1_table[256];
179 static int rr_tf1_tblptr = 0;
180 
181 double rr_ctf1_fcn (double *x, double* par)
182 {
183  TF1 *fcn = (TF1 *)TF1::GetCurrent();
184  struct rr_fcn_info *info = NULL;
185 
186  for (int i = 0; i < rr_tf1_tblptr; i++)
187  {
188  info = rr_tf1_table[i];
189  if (!strcmp(info->name, fcn->GetName()))
190  break;
191  else
192  info = NULL;
193  }
194 
195  if (info == NULL) {
196  rb_warn("Ruby user defined function has not been registered for %s (%p).",
197  fcn->GetName(), fcn);
198  return 0.;
199  }
200 
201  int n = fcn->GetNpar();
202  VALUE vx = rb_ary_new2 (n);
203  VALUE vpar = rb_ary_new2 (n);
204  for (int i = 0; i < n; i++)
205  {
206  rb_ary_push (vx, rb_float_new(x[i]));
207  rb_ary_push (vpar, rb_float_new(par[i]));
208  }
209 
210  double res = NUM2DBL(rb_funcall (rb_cObject, info->id, 2, vx, vpar));
211  return res;
212 }
213 
214 void rr_register_ctf1_fcn (char *name, ID id)
215 {
216  struct rr_fcn_info *info = (struct rr_fcn_info *)malloc (sizeof *info);
217 
218  info->name = strdup(name);
219  info->id = id;
220 
221  rr_tf1_table[rr_tf1_tblptr] = info;
222  rr_tf1_tblptr++;
223 
224 }
225 
226 static struct rr_fcn_info * rr_tf2_table[256];
227 static int rr_tf2_tblptr = 0;
228 
229 double rr_ctf2_fcn (double *x, double* par)
230 {
231  TF2 *fcn = (TF2 *)TF2::GetCurrent();
232  struct rr_fcn_info *info = NULL;
233 
234  for (int i = 0; i < rr_tf2_tblptr; i++)
235  {
236  info = rr_tf2_table[i];
237  if (!strcmp(info->name, fcn->GetName()))
238  break;
239  else
240  info = NULL;
241  }
242 
243  if (info == NULL) {
244  rb_warn("Ruby user defined function has not been registered for %s (%p).",
245  fcn->GetName(), fcn);
246  return 0.;
247  }
248 
249  int n = fcn->GetNpar();
250  VALUE vx = rb_ary_new2 (n);
251  VALUE vpar = rb_ary_new2 (n);
252  for (int i = 0; i < n; i++)
253  {
254  rb_ary_push (vx, rb_float_new(x[i]));
255  rb_ary_push (vpar, rb_float_new(par[i]));
256  }
257 
258  double res = NUM2DBL(rb_funcall (rb_cObject, info->id, 2, vx, vpar));
259  return res;
260 }
261 
262 void rr_register_ctf2_fcn (char *name, ID id)
263 {
264  struct rr_fcn_info *info = (struct rr_fcn_info *)malloc (sizeof *info);
265 
266  info->name = strdup(name);
267  info->id = id;
268 
269  rr_tf2_table[rr_tf2_tblptr] = info;
270  rr_tf2_tblptr++;
271 
272 }
273 /* Implementation */
274 
275 /* Globals */
276 
277 static VALUE rr_gsystem (void)
278 {
279  VALUE o;
280 
281  RRNEW(o, cTObject);
282  rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gSystem));
283  rb_iv_set (o, "__rr_class__", rb_str_new2("TSystem"));
284 
285  return o;
286 }
287 
288 static VALUE rr_grandom (void)
289 {
290  VALUE o;
291 
292  RRNEW(o, cTObject);
293  rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gRandom));
294  rb_iv_set (o, "__rr_class__", rb_str_new2("TRandom"));
295 
296  return o;
297 }
298 
299 static VALUE rr_gbenchmark (void)
300 {
301  VALUE o;
302 
303  RRNEW(o, cTObject);
304  rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gBenchmark));
305  rb_iv_set (o, "__rr_class__", rb_str_new2("TBenchmark"));
306 
307  return o;
308 }
309 
310 static VALUE rr_gpad (void)
311 {
312  VALUE o;
313 
314  RRNEW(o, cTObject);
315  rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gPad));
316  rb_iv_set (o, "__rr_class__", rb_str_new2("TPad"));
317 
318  return o;
319 }
320 
321 static VALUE rr_gstyle (void)
322 {
323  VALUE o;
324 
325  RRNEW(o, cTObject);
326  rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gStyle));
327  rb_iv_set (o, "__rr_class__", rb_str_new2("TStyle"));
328 
329  return o;
330 }
331 
332 static VALUE rr_gdirectory (void)
333 {
334  VALUE o;
335 
336  RRNEW(o, cTObject);
337  rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gDirectory));
338  rb_iv_set (o, "__rr_class__", rb_str_new2("TDirectory"));
339 
340  return o;
341 }
342 
343 static VALUE rr_groot (void)
344 {
345  VALUE o;
346 
347  RRNEW(o, cTObject);
348 
349  rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gROOT));
350  rb_iv_set (o, "__rr_class__", rb_str_new2("TROOT"));
351 
352  return o;
353 }
354 
355 static VALUE rr_gapplication (void)
356 {
357  VALUE o;
358 
359  RRNEW(o, cTObject);
360 
361  rb_iv_set (o, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, gApplication));
362  rb_iv_set (o, "__rr_class__", rb_str_new2("TApplication"));
363 
364  return o;
365 }
366 
367 static VALUE via (VALUE self, VALUE ameth, VALUE bmeth, VALUE parms)
368 {
369  if (TYPE(ameth) != T_SYMBOL &&
370  TYPE(bmeth) != T_SYMBOL &&
371  TYPE(parms) != T_HASH)
372  {
373  rb_fatal ("rr-via: Please call TObject#via with sym, sym, hash.");
374  return Qnil;
375  }
376 
377  VALUE keys = rb_funcall(parms, rb_intern("keys"), 0);
378  for (int i = 0; i < RARRAY_LEN(keys); i++)
379  {
380  VALUE key = rb_ary_entry (keys, i);
381  rb_funcall (self, rb_to_id (ameth), 2, key, rb_hash_aref (parms, key));
382  }
383  rb_funcall(self, rb_to_id(bmeth), 0);
384 
385  return self;
386 }
387 
388 /* Dynamic ruby-root specific implementation. */
389 
391 {
392  static TObject *o;
393  Data_Get_Struct(rb_iv_get (self, "__rr__"), TObject, o);
394  return o;
395 }
396 
397 UInt_t drr_map_args2(VALUE inargs, char *cproto, int cproto_size, G__CallFunc *f,
398  Long_t offset=1, UInt_t reference_map=0x0)
399 {
400  /* FIXME. Offset reminds me fortran code; make a better interface,
401  * and change the function name to a better one.
402  *
403  * The boolean checks for cproto and f are vital. This function can
404  * be called:
405  *
406  * 1. When we want a C prototype from a Ruby call
407  * 2. When we want to set the arguments of a CINT function
408  * 3. When we want both 1 and 2
409  */
410 
411  int nargs = RARRAY_LEN(inargs) - offset;
412  double *arr = NULL;
413  TObject *ptr = NULL;
414  VALUE v = 0;
415 
416  UInt_t ntobjects = 0;
417 
418  /* Transform Ruby arguments to C/C++. */
419  for (int i = 0; i < nargs; i++)
420  {
421  VALUE arg = rb_ary_entry (inargs, i+offset);
422  switch (TYPE(arg))
423  {
424  case T_FIXNUM:
425  if (f) f->SetArg((Long_t) NUM2INT(arg));
426  if (cproto) strlcat(cproto, "int", cproto_size);
427  break;
428  case T_FLOAT:
429  if (f) f->SetArg(NUM2DBL(arg));
430  if (cproto) strlcat(cproto, "double", cproto_size);
431  break;
432  case T_STRING:
433  if (f) f->SetArg((Long_t) StringValuePtr(arg));
434  if (cproto) strlcat(cproto, "char*", cproto_size);
435  break;
436  case T_ARRAY:
437  /* FIXME: Handle all arrays, not only
438  * with floats.
439  */
440  if (f)
441  {
442  arr = ALLOC_N (double, RARRAY_LEN(arg));
443  for (int j = 0; j < RARRAY_LEN(arg); j++)
444  arr[j] = NUM2DBL(rb_ary_entry (arg, j));
445  f->SetArg((Long_t) arr);
446  }
447  if (cproto) strlcat(cproto, "double*", cproto_size);
448  break;
449  case T_OBJECT:
450  v = rb_iv_get (arg, "__rr__");
451  if (!NIL_P(v))
452  {
453  Data_Get_Struct (v, TObject, ptr);
454  if (f) f->SetArg((Long_t) ptr);
455  if (cproto) {
456  VALUE tmp = rb_iv_get (arg, "__rr_class__");
457  strlcat(cproto, StringValuePtr(tmp), cproto_size);
458  if( ((reference_map>>ntobjects)&0x1) ) {
459  strlcat(cproto, "*", cproto_size);
460  } else {
461  strlcat(cproto, "&", cproto_size);
462  }
463  }
464  }
465  ++ntobjects;
466  break;
467  default:
468  break;
469  }
470  if ((i + 1 < nargs) && (nargs != 1) && cproto)
471  strlcat(cproto, ",", cproto_size);
472  }
473  return ntobjects;
474 }
475 
476 void drr_find_method_prototype( G__ClassInfo *klass, char *methname, VALUE inargs,
477  char *cproto, int cproto_size, Long_t offset )
478 {
479  /* FIXME: Brute force checking of all combinations of * and & for
480  * T_Objects Since we cannot tell which one is needed (we get the type
481  * from the ruby objects, which don't know) we try all.
482  */
483 
484  G__MethodInfo *minfo = 0;
485  Long_t dummy_offset = 0; // Not read out, but expected by GetMethod
486 
487  // Number of T_OBJECTS in argument list initialized to more than 1
488  UInt_t nobjects = drr_map_args2 (inargs, cproto, cproto_size, 0, offset, 0x0);
489  // 2^nobjects == number of combinations of "*" and "&"
490  UInt_t bitmap_end = static_cast<UInt_t>( 0x1 << nobjects );
491 
492  // Check if method methname with prototype cproto is present in klass
493  minfo = new G__MethodInfo(klass->GetMethod(methname, cproto, &dummy_offset));
494 
495  /* Loop if we have to, i.e. there are T_OBJECTS ^= TObjects and the first
496  * combination is not correct.
497  */
498  if( nobjects > 0 && !(minfo->IsValid()) ) {
499  for( UInt_t reference_map=0x1; reference_map < bitmap_end; reference_map++) {
500  cproto[0] = static_cast<char>( 0 ); // reset cproto
501  drr_map_args2 (inargs, cproto, cproto_size, 0, offset, reference_map);
502  minfo = new G__MethodInfo(klass->GetMethod(methname, cproto, &dummy_offset));
503  if (minfo->IsValid())
504  break;
505  }
506  }
507 
508  delete minfo;
509 
510  return;
511 }
512 
513 void drr_set_method_args( VALUE inargs, G__CallFunc *func, Long_t offset=1 )
514 {
515  drr_map_args2( inargs, 0, 0, func, offset );
516 }
517 
519 
520 int drr_parse_ret_type (const char *ret)
521 {
522  char *realtype = strdup(ret), *t = realtype;
523  int plevel = 0;
524  Ektype type;
525 
526  while (*(t++)) {
527  if (*t == '*')
528  plevel++;
529  }
530 
531  t--;
532 
533  if (plevel > 0)
534  *(t - plevel) = '\0';
535 
536  if (!strncmp(t - 3, "int", 3) ||
537  !strncmp(t - 4, "long", 4))
538  type = kint;
539  else
540  if (!strncmp(t - 6, "double", 6) ||
541  !strncmp(t - 5, "float", 5))
542  type = kfloat;
543  else
544  if (!strncmp(t - 5, "char", 4))
545  type = kchar;
546  else
547  if (!strncmp(t - 4, "void", 4))
548  type = kvoid;
549  else
550  if (!strncmp(t - 4, "bool", 4))
551  type = kbool;
552  else
553  type = kunknown;
554 
555  if (plevel)
556  /* Quick hack to move from ordinary types to pointer types,
557  * which are essntially arrays of values. For example an integer
558  * (kint) is transformed to an array of integers (kintary). */
559  type = (Ektype)(type + 5);
560 
561  free (realtype);
562 
563  return type;
564 }
565 
566 /* Function cache related. */
567 
569 {
570  struct drr_func_cache *new_cache = (struct drr_func_cache *) malloc (sizeof *new_cache);
571  new_cache->next = NULL;
572  new_cache->entry = entry;
573  new_cache->last = NULL;
574  return new_cache;
575 }
576 
578 {
579  struct drr_func_cache *n = (struct drr_func_cache *) malloc(sizeof *n);
580  n->entry = entry;
581 
582  if (cache->next)
583  {
584  n->next = cache->next;
585  cache->next = n;
586  }
587  else
588  {
589  cache->next = n;
590  n->next = NULL;
591  }
592 }
593 
594 struct drr_func_entry * drr_func_cache_find (struct drr_func_cache *cache, char *name)
595 {
596  struct drr_func_cache *iter = cache;
597 
598  while (iter)
599  {
600  if (!strcmp (iter->entry->name, name))
601  return iter->entry;
602  iter = iter->next;
603  }
604  return NULL;
605 }
606 
608 {
609  delete entry->func;
610  delete entry->klass;
611  free (entry->name);
612  free (entry->cproto);
613  free (entry);
614 }
615 
616 /* Ruby generic interface. */
617 
619 
620 static VALUE drr_as(VALUE self, VALUE klass)
621 {
622  /* Pseudo C++ casting. */
623  VALUE v;
624 
625  /* Check if there is a ROOT dict. available. */
626  TClass *c = TClass::GetClass(StringValuePtr(klass));
627  if (c)
628  {
629  VALUE k;
630  char *name = StringValuePtr(klass);
631  if (!rb_const_defined (rb_cObject, rb_intern(name)))
632  k = rb_define_class (name, drrAbstractClass);
633  else
634  k = rb_path2class (name);
635 
636  RRNEW(v, k);
637  rb_iv_set (v, "__rr__", rb_iv_get(self, "__rr__"));
638  rb_iv_set (v, "__rr_class__", klass);
639  }
640  else
641  rb_raise( rb_eArgError, "No TClass found for %s. Is this a Root type?", StringValuePtr(klass) );
642 
643  return v;
644 }
645 
646 static VALUE drr_init(int argc, VALUE argv[], VALUE self)
647 {
648  VALUE inargs;
649  char *classname = (char*) rb_obj_classname(self);
650  char cproto[1024] = "";
651  Long_t addr = 0;
652  Long_t offset = 0;
653 
654  rb_scan_args (argc, argv, "0*", &inargs);
655 
656  G__CallFunc* func = new G__CallFunc();
657  G__ClassInfo klass(classname);
658 
659  /* Call the requested ctor. */
660 
661  if (RARRAY_LEN(inargs)) {
662  drr_find_method_prototype (&klass, classname, inargs, cproto, sizeof(cproto), 0);
663  drr_set_method_args ( inargs, func, 0);
664  }
665 
666  G__MethodInfo minfo(klass.GetMethod(classname, cproto, &offset));
667  if (minfo.IsValid())
668  func->SetFunc(minfo);
669  else
670  rb_raise( rb_eArgError, "You provided an unknown prototype (%s) for (%s#%s).",
671  cproto, classname, classname);
672 
673  addr = func->ExecInt((void*)((Long_t)0 + offset));
674  rb_iv_set(self, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, (TObject *)addr));
675  rb_iv_set(self, "__rr_class__", rb_str_new2 (classname));
676 
677  func->Init();
678  delete func;
679  return self;
680 }
681 
682 static VALUE drr_return(int rtype, Long_t value_address, double dvalue_address, VALUE self)
683 {
684  VALUE vret;
685 
686  switch (rtype)
687  {
688  case kint:
689  vret = INT2NUM(value_address);
690  break;
691  case kfloat:
692  vret = rb_float_new(dvalue_address);
693  break;
694  case kstring:
695  vret = rb_str_new2((char *)value_address);
696  break;
697  case kbool:
698  vret = rr_bool((bool)value_address);
699  break;
700  case kroot:
701  if (!value_address)
702  return Qnil;
703 
704  if (!strcmp(((TObject*)(value_address))->ClassName(), "TList"))
705  vret = rr_ary_new((TList*)value_address);
706  else
707  {
708  VALUE res;
709  RRNEW(res, cTObject);
710  rb_iv_set(res, "__rr__", Data_Wrap_Struct(cTObject, 0, 0, (TObject*)value_address));
711  rb_iv_set(res, "__rr_class__", rb_str_new2 (((TObject*)(value_address))->ClassName()));
712  vret = res;
713  }
714 
715  break;
716 
717  default:
718  vret = self;
719  break;
720  }
721 
722  return vret;
723 }
724 
725 
726 static VALUE drr_const_missing(VALUE self, VALUE klass)
727 {
728  /* Define a new ROOT Class dynammically. */
729 
730  char *name = (char*) rb_id2name (rb_to_id(klass));
731 
732  /* Check if there is a ROOT dict. available. */
733  TClass *c = new TClass(name);
734  if (c && c->GetClassInfo()) {
735  VALUE new_klass = rb_define_class (name, drrAbstractClass);
736  delete c;
737  return new_klass;
738  } else {
739  delete c;
740  /* If there is no ROOT dict available, call the original Object::const_missing */
741  return rb_funcall(self,rb_intern("__drr_orig_const_missing"),1,klass);
742  }
743 }
744 
745 static VALUE drr_singleton_missing(int argc, VALUE argv[], VALUE self)
746 {
747  VALUE inargs;
748  char cproto[1024] = "";
749  int nargs;
750  Long_t offset = 0;
751  Long_t address = 0;
752  double dbladdr = 0;
753 
754  /* Call a singleton method. */
755  char * methname = (char*) rb_id2name (rb_to_id(argv[0]));
756  char * classname = (char *) rb_class2name(self);
757 
758  rb_scan_args (argc, argv, "0*", &inargs);
759  nargs = RARRAY_LEN(inargs) - 1;
760 
761  G__CallFunc* func = new G__CallFunc;
762  G__ClassInfo *klass = new G__ClassInfo (classname);
763  G__MethodInfo *minfo = 0;
764 
765  if (nargs) {
766  drr_find_method_prototype( klass, methname, inargs, cproto, sizeof(cproto), 1 );
767  drr_set_method_args( inargs, func, 1 );
768  }
769 
770  /* FIXME: minfo is really used only for the return type. */
771  minfo = new G__MethodInfo(klass->GetMethod(methname, cproto, &offset));
772  if (minfo->IsValid())
773  func->SetFunc(*minfo);
774  else
775  rb_raise( rb_eArgError, "You provided an unknown prototype (%s) for (%s#%s).",
776  cproto, classname, methname);
777 
778  int rtype = drr_parse_ret_type (minfo->Type()->TrueName());
779  delete minfo;
780 
781  if (rtype != kfloat)
782  address = func->ExecInt((void*)(offset));
783  else
784  dbladdr = func->ExecDouble((void*)(offset));
785 
786  VALUE ret = drr_return(rtype, address, dbladdr, self);
787  delete func;
788  return ret;
789 }
790 
791 
792 static VALUE drr_method_missing(int argc, VALUE argv[], VALUE self)
793 {
794  /* When a ROOT method is called, we try to resolve it here. If
795  * CINT is able to resolve it then we define a Ruby method using
796  * a similar generic function (drr_generic_method), so as
797  * Ruby not to use the Object#method_missing every time.
798  */
799 
800  VALUE inargs;
801  char *methname, *classname ;
802  Long_t offset = 0;
803  Long_t address = 0;
804  double dbladdr = 0;
805  char cproto[1024] = "";
806  int nargs;
807 
808  /* Grab method, class and the instance pointer. */
809  methname = (char*) rb_id2name (rb_to_id(argv[0]));
810  VALUE tmp = rb_iv_get (self, "__rr_class__");
811  classname = StringValuePtr(tmp);
812  TObject *caller = drr_grab_object (self);
813 
814  rb_scan_args (argc, argv, "0*", &inargs);
815 
816  nargs = RARRAY_LEN(inargs) - 1;
817  VALUE rklass = rb_class_of (self);
818 
819  G__CallFunc *func = new G__CallFunc();
820  G__ClassInfo *klass = new G__ClassInfo (classname);
821  G__MethodInfo *minfo = 0;
822 
823  if (nargs) {
824  drr_find_method_prototype( klass, methname, inargs, cproto, sizeof(cproto), 1 );
825  drr_set_method_args( inargs, func, 1 );
826  }
827 
828  /* FIXME: minfo is really used only for the return type. */
829  minfo = new G__MethodInfo(klass->GetMethod(methname, cproto, &offset));
830  if (minfo->IsValid())
831  func->SetFunc(*minfo);
832  else
833  rb_raise( rb_eArgError, "You provided an unknown prototype (%s) for (%s#%s).",
834  cproto, classname, methname);
835 
836  /* This is the first time this method is called. Create a cash entry. */
837  struct drr_func_entry *entry = (struct drr_func_entry *) malloc (sizeof *entry);
838  entry->func = func;
839  entry->klass = klass;
840  entry->name = strdup(methname);
841  entry->cproto = strdup(cproto);
842  entry->rtype = drr_parse_ret_type (minfo->Type()->TrueName());
843 
844  delete minfo;
845 
846  struct drr_func_cache *cache;
847  /* If there is no cache available, create one (per Class scope). */
848  if (!rb_cvar_defined (rklass, rb_intern("@@__func_table__")))
849  cache = drr_func_cache_init (entry);
850  else
851  Data_Get_Struct(rb_cv_get(rklass, "@@__func_table__"), struct drr_func_cache, cache);
852 
853  /* Push the method to the cache and save it back to the Class. */
854  drr_func_cache_push (cache, entry);
855  rb_cv_set (rklass, "@@__func_table__",
856  Data_Wrap_Struct(cTObject, 0, 0, cache));
857 
858  if (entry->rtype != kfloat)
859  address = func->ExecInt((void*)((Long_t)caller + offset));
860  else
861  dbladdr = func->ExecDouble((void*)((Long_t)caller + offset));
862 
863  /* Define method. */
864  rb_define_method (rklass, methname, VALUEFUNC(drr_generic_method), -1);
865 
866  return(drr_return(entry->rtype, address, dbladdr, self));
867 }
868 
869 static VALUE drr_generic_method(int argc, VALUE argv[], VALUE self)
870 {
871  VALUE inargs;
872  VALUE rklass;
873  int nargs;
874  Long_t offset = 0, address = 0;
875  double dbladdr = 0;
876  char cproto[1024] = "";
877 
878  /* Grab class, method name and instance pointer. */
879  rklass = rb_class_of (self);
880  char *methname = (char*) rb_id2name (rb_frame_this_func());
881  TObject *caller = drr_grab_object (self);
882 
883  rb_scan_args (argc, argv, "0*", &inargs);
884 
885  nargs = RARRAY_LEN(inargs);
886 
887  G__CallFunc *func = NULL;
888 
889  struct drr_func_cache *cache;
890  struct drr_func_entry *entry;
891 
892  Data_Get_Struct (rb_cv_get(rklass, "@@__func_table__"), struct drr_func_cache, cache);
893  entry = drr_func_cache_find (cache, methname);
894 
895  if (entry)
896  {
897  func = entry->func;
898  if (nargs)
899  drr_find_method_prototype (entry->klass, methname, inargs, cproto, sizeof(cproto), 0);
900  func->SetFuncProto (entry->klass, methname, cproto, &offset);
901  /* FIXME: Why on earth CINT resets the arguments when
902  * SetFuncProto() is called?
903  */
904  if (nargs)
905  drr_set_method_args (inargs, func, 0);
906  }
907  else {
908  /* FIXME: This can never be happened. */
909  rb_warn ("Proto conflict with cache. Expected %s, but found no match for %s", cproto, methname);
910  return VALUE();
911  }
912 
913  if (entry->rtype != kfloat)
914  address = func->ExecInt((void*)((Long_t)caller + offset));
915  else
916  dbladdr = func->ExecDouble((void*)((Long_t)caller + offset));
917 
918  return(drr_return(entry->rtype, address, dbladdr, self));
919 }
920 
921 extern "C"
922 void Init_libRuby() {
923 
924  /* In order to have the most frequently used dictionaries
925  * loaded by default. THIS MUST BE REPLACED BY PORTABLE CODE */
926 #if defined(linux) || defined(sun)
927  dlopen( "libCint.so", RTLD_GLOBAL | RTLD_LAZY );
928  dlopen( "libCore.so", RTLD_GLOBAL | RTLD_LAZY );
929  dlopen( "libGpad.so", RTLD_GLOBAL | RTLD_LAZY );
930  dlopen( "libGraf.so", RTLD_GLOBAL | RTLD_LAZY );
931  dlopen( "libMatrix.so", RTLD_GLOBAL | RTLD_LAZY );
932  dlopen( "libHist.so", RTLD_GLOBAL | RTLD_LAZY );
933  dlopen( "libTree.so", RTLD_GLOBAL | RTLD_LAZY );
934  dlopen( "libGraf3d.so", RTLD_GLOBAL | RTLD_LAZY );
935  dlopen( "libGeom.so", RTLD_GLOBAL | RTLD_LAZY );
936 #endif
937 
938  /* Create a new ROOT Application if it doesn't already exist. */
939  if (!gApplication)
940  gApplication = new TApplication("ruby root app", NULL, NULL);
941 
942  drrAbstractClass = rb_define_class("DRRAbstractClass", rb_cObject);
943  rb_define_method(drrAbstractClass, "initialize", VALUEFUNC(drr_init), -1);
944  rb_define_method(drrAbstractClass, "method_missing", VALUEFUNC(drr_method_missing), -1);
945  rb_define_method (drrAbstractClass, "as", VALUEFUNC(drr_as), 1);
946  /* For singleton function calls. */
947  rb_define_singleton_method (drrAbstractClass, "method_missing", VALUEFUNC(drr_singleton_missing), -1);
948 
949  cTObject = rb_define_class("TObject", drrAbstractClass);
950 
951  rb_define_method (cTObject, "to_ary", VALUEFUNC(rr_to_ary), 0);
952  rb_define_method (rb_cObject, "via", VALUEFUNC(via), 3);
953 
954  /* Save the original Object::const_missing before overriding it
955  Object::__drr_orig_const_missing will be called if Cint is unable to resolve the class name */
956  rb_eval_string("Object.instance_eval { alias __drr_orig_const_missing const_missing }");
957  rb_define_singleton_method (rb_cObject, "const_missing", VALUEFUNC(drr_const_missing), 1);
958 
959  /* usefull globals */
960  rb_define_method (rb_cObject, "gSystem", VALUEFUNC(rr_gsystem), 0);
961  rb_define_method (rb_cObject, "gRandom", VALUEFUNC(rr_grandom), 0);
962  rb_define_method (rb_cObject, "gBenchmark", VALUEFUNC(rr_gbenchmark), 0);
963  rb_define_method (rb_cObject, "gPad", VALUEFUNC(rr_gpad), 0);
964  rb_define_method (rb_cObject, "gStyle", VALUEFUNC(rr_gstyle), 0);
965  rb_define_method (rb_cObject, "gDirectory", VALUEFUNC(rr_gdirectory), 0);
966  rb_define_method (rb_cObject, "gROOT", VALUEFUNC(rr_groot), 0);
967  rb_define_method (rb_cObject, "gApplication", VALUEFUNC(rr_gapplication), 0);
968 
969  /* enums */
971 }
Double_t At(Int_t i) const
Definition: TArrayD.h:81
double par[1]
Definition: unuranDistr.cxx:38
int rtype
Definition: rrcommon.h:132
Definition: rrcommon.h:127
static int rr_tf2_tblptr
Definition: drr.cxx:227
double rr_ctf1_fcn(double *x, double *par)
Definition: drr.cxx:181
void Init_libRuby()
Definition: drr.cxx:922
void init_global_enums(void)
Definition: rrenums.h:202
Definition: drr.cxx:518
Definition: drr.cxx:518
ClassImp(TSeqCollection) Int_t TSeqCollection TIter next(this)
Return index of object in collection.
VALUE rr_seqcollection_new(TSeqCollection *sc)
Definition: drr.cxx:150
R__EXTERN TStyle * gStyle
Definition: TStyle.h:423
void drr_find_method_prototype(G__ClassInfo *klass, char *methname, VALUE inargs, char *cproto, int cproto_size, Long_t offset)
Definition: drr.cxx:476
#define gDirectory
Definition: TDirectory.h:218
static TF1 * GetCurrent()
Static function returning the current function being processed.
Definition: TF1.cxx:1288
struct drr_func_entry * entry
Definition: rrcommon.h:136
static VALUE drr_const_missing(VALUE self, VALUE klass)
Definition: drr.cxx:726
struct drr_func_entry * drr_func_cache_find(struct drr_func_cache *cache, char *name)
Definition: drr.cxx:594
static VALUE rr_gstyle(void)
Definition: drr.cxx:321
#define gROOT
Definition: TROOT.h:340
int drr_parse_ret_type(const char *ret)
Definition: drr.cxx:520
Definition: drr.cxx:518
Array of floats (32 bits per element).
Definition: TArrayF.h:29
struct drr_func_cache * drr_func_cache_init(struct drr_func_entry *entry)
Definition: drr.cxx:568
bool Bool_t
Definition: RtypesCore.h:59
TArc * a
Definition: textangle.C:12
Definition: drr.cxx:518
R__EXTERN TApplication * gApplication
Definition: TApplication.h:171
Definition: drr.cxx:518
Array of integers (32 bits per element).
Definition: TArrayI.h:29
Definition: drr.cxx:518
VALUE rr_arrayd_new(const TArrayD *a)
Definition: drr.cxx:139
Sequenceable collection abstract base class.
TObject * drr_grab_object(VALUE self)
Definition: drr.cxx:390
VALUE rr_ary_new(TList *l)
Definition: drr.cxx:56
Double_t x[n]
Definition: legend1.C:17
Vc_ALWAYS_INLINE void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: memory.h:94
Definition: drr.cxx:518
std::map< std::string, std::string >::const_iterator iter
Definition: TAlienJob.cxx:54
void drr_set_method_args(VALUE inargs, G__CallFunc *func, Long_t offset=1)
Definition: drr.cxx:513
const std::string ClassName(PyObject *pyobj)
Retrieve the class name from the given python object (which may be just an instance of the class)...
Definition: Utility.cxx:691
static VALUE rr_to_ary(VALUE self)
Definition: drr.cxx:77
Char_t At(Int_t i) const
Definition: TArrayC.h:80
XFontStruct * id
Definition: TGX11.cxx:108
void drr_func_cache_push(struct drr_func_cache *cache, struct drr_func_entry *entry)
Definition: drr.cxx:577
Short_t At(Int_t i) const
Definition: TArrayS.h:80
VALUE rr_arrayc_new(const TArrayC *a)
Definition: drr.cxx:84
A doubly linked list.
Definition: TList.h:47
Long_t At(Int_t i) const
Definition: TArrayL.h:82
VALUE rr_arrayi_new(const TArrayI *a)
Definition: drr.cxx:106
UInt_t drr_map_args2(VALUE inargs, char *cproto, int cproto_size, G__CallFunc *f, Long_t offset=1, UInt_t reference_map=0x0)
Definition: drr.cxx:397
static VALUE drr_method_missing(int argc, VALUE argv[], VALUE self)
Definition: drr.cxx:792
static VALUE rr_gapplication(void)
Definition: drr.cxx:355
static VALUE rr_gsystem(void)
Definition: drr.cxx:277
VALUE rr_bool(Bool_t q)
Definition: drr.cxx:166
char * name
Definition: rrcommon.h:130
R__EXTERN TSystem * gSystem
Definition: TSystem.h:549
Array of shorts (16 bits per element).
Definition: TArrayS.h:29
SVector< double, 2 > v
Definition: Dict.h:5
void rr_register_ctf1_fcn(char *name, ID id)
Definition: drr.cxx:214
char * cproto
Definition: rrcommon.h:131
R__EXTERN TBenchmark * gBenchmark
Definition: TBenchmark.h:63
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:187
ClassInfo_t * GetClassInfo() const
Definition: TClass.h:391
Ektype
Definition: drr.cxx:518
unsigned int UInt_t
Definition: RtypesCore.h:42
Array of longs (32 or 64 bits per element).
Definition: TArrayL.h:29
static VALUE drr_as(VALUE self, VALUE klass)
Definition: drr.cxx:620
TLine * l
Definition: textangle.C:4
static VALUE drr_singleton_missing(int argc, VALUE argv[], VALUE self)
Definition: drr.cxx:745
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
static VALUE drr_generic_method(int argc, VALUE argv[], VALUE self)
Definition: drr.cxx:869
A 2-Dim function with parameters.
Definition: TF2.h:33
R__EXTERN TRandom * gRandom
Definition: TRandom.h:62
Long64_t entry
struct drr_func_cache * last
Definition: rrcommon.h:138
Int_t GetSize() const
Definition: TArray.h:49
#define rb_frame_this_func
Definition: drr.cxx:50
long Long_t
Definition: RtypesCore.h:50
struct drr_func_cache * next
Definition: rrcommon.h:137
char * name
Definition: rrcommon.h:112
virtual Int_t GetSize() const
Definition: TCollection.h:95
static const double x1[5]
double f(double x)
static VALUE rr_gpad(void)
Definition: drr.cxx:310
Int_t At(Int_t i) const
Definition: TArrayI.h:81
int type
Definition: TGX11.cxx:120
double func(double *x, double *p)
Definition: stressTF1.cxx:213
static VALUE via(VALUE self, VALUE ameth, VALUE bmeth, VALUE parms)
Definition: drr.cxx:367
static int rr_tf1_tblptr
Definition: drr.cxx:179
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2881
Float_t At(Int_t i) const
Definition: TArrayF.h:80
Array of doubles (64 bits per element).
Definition: TArrayD.h:29
#define name(a, b)
Definition: linkTestLib0.cpp:5
virtual TObject * At(Int_t idx) const =0
Mother of all ROOT objects.
Definition: TObject.h:58
static VALUE rr_gdirectory(void)
Definition: drr.cxx:332
VALUE rr_arrays_new(const TArrayS *a)
Definition: drr.cxx:95
1-Dim function class
Definition: TF1.h:149
void drr_func_entry_free(struct drr_func_entry *entry)
Definition: drr.cxx:607
VALUE cTObject
Definition: drr.cxx:54
#define NULL
Definition: Rtypes.h:82
#define gPad
Definition: TVirtualPad.h:288
VALUE rr_arrayl_new(const TArrayL *a)
Definition: drr.cxx:117
void rr_register_ctf2_fcn(char *name, ID id)
Definition: drr.cxx:262
#define VALUEFUNC(f)
Definition: rrcommon.h:48
This class creates the ROOT Application Environment that interfaces to the windowing system eventloop...
Definition: TApplication.h:45
#define RRNEW(obj, type)
Definition: rrcommon.h:54
static VALUE rr_groot(void)
Definition: drr.cxx:343
float * q
Definition: THbookFile.cxx:87
G__ClassInfo * klass
Definition: rrcommon.h:129
Vc_ALWAYS_INLINE_L T *Vc_ALWAYS_INLINE_R malloc(size_t n)
Allocates memory on the Heap with alignment and padding suitable for vectorized access.
Definition: memory.h:67
VALUE drrAbstractClass
Definition: drr.cxx:618
static VALUE rr_grandom(void)
Definition: drr.cxx:288
const Int_t n
Definition: legend1.C:16
G__CallFunc * func
Definition: rrcommon.h:128
virtual Int_t GetNpar() const
Definition: TF1.h:349
#define RRGRAB(fromobj, type, toobj)
Definition: rrcommon.h:56
static VALUE drr_return(int rtype, Long_t value_address, double dvalue_address, VALUE self)
Definition: drr.cxx:682
double rr_ctf2_fcn(double *x, double *par)
Definition: drr.cxx:229
static VALUE drr_init(int argc, VALUE argv[], VALUE self)
Definition: drr.cxx:646
Definition: drr.cxx:518
#define RARRAY_LEN(s)
Definition: drr.cxx:36
static VALUE rr_gbenchmark(void)
Definition: drr.cxx:299
VALUE rr_arrayf_new(const TArrayF *a)
Definition: drr.cxx:128
Array of chars or bytes (8 bits per element).
Definition: TArrayC.h:29