aboutsummaryrefslogtreecommitdiff
path: root/externals/gridflow/base/grid.c
diff options
context:
space:
mode:
Diffstat (limited to 'externals/gridflow/base/grid.c')
-rw-r--r--externals/gridflow/base/grid.c604
1 files changed, 604 insertions, 0 deletions
diff --git a/externals/gridflow/base/grid.c b/externals/gridflow/base/grid.c
new file mode 100644
index 00000000..877a460f
--- /dev/null
+++ b/externals/gridflow/base/grid.c
@@ -0,0 +1,604 @@
+/*
+ $Id: grid.c,v 1.1 2005-10-04 02:02:13 matju Exp $
+
+ GridFlow
+ Copyright (c) 2001,2002,2003,2004 by Mathieu Bouchard
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include "grid.h.fcs"
+#include <ctype.h>
+
+/* copied from bridge/puredata.c (sorry: linkage issue) */
+struct Pointer : CObject { void *p; Pointer(void *_p) : p(_p) {}};
+Ruby Pointer_s_noo (void *ptr) {
+ return Data_Wrap_Struct(EVAL("GridFlow::Pointer"), 0, 0, new Pointer(ptr));}
+static void *Pointer_gut (Ruby rself) {DGS(Pointer); return self->p;}
+
+//#define TRACE fprintf(stderr,"%s %s [%s:%d]\n",INFO(parent),__PRETTY_FUNCTION__,__FILE__,__LINE__);assert(this);
+#define TRACE assert(this);
+
+#define CHECK_TYPE(d) \
+ if (NumberTypeE_type_of(d)!=this->nt) RAISE("%s(%s): " \
+ "type mismatch during transmission (got %s expecting %s)", \
+ INFO(parent), \
+ __PRETTY_FUNCTION__, \
+ number_type_table[NumberTypeE_type_of(d)].name, \
+ number_type_table[this->nt].name);
+
+#define CHECK_BUSY(s) \
+ if (!dim) RAISE("%s: " #s " not busy",INFO(parent));
+
+#define CHECK_ALIGN(d) \
+ {int bytes = number_type_table[nt].size/8; \
+ int align = ((long)(void*)d)%bytes; \
+ if (align) {L;gfpost("%s(%s): Alignment Warning: %p is not %d-aligned: %d", \
+ INFO(parent), __PRETTY_FUNCTION__, (void*)d,bytes,align);}}
+
+#define CHECK_ALIGN2(d,nt) \
+ {int bytes = number_type_table[nt].size/8; \
+ int align = ((long)(void*)d)%bytes; \
+ if (align) {L;gfpost("Alignment Warning: %p is not %d-aligned: %d", \
+ (void*)d,bytes,align);}}
+
+// **************** Grid ******************************************
+
+#define FOO(S) static inline void NUM(Ruby x, S &y) {y=convert(x,(int32*)0);}
+EACH_INT_TYPE(FOO)
+#undef FOO
+
+#define FOO(S) \
+static inline void NUM(Ruby x, S &y) { \
+ if (TYPE(x)==T_FLOAT) y = RFLOAT(x)->value; \
+ else if (INTEGER_P(x)) y = convert(x,(S*)0); \
+ else RAISE("expected Float (or at least Integer)");}
+EACH_FLOAT_TYPE(FOO)
+#undef FOO
+
+void Grid::init_from_ruby_list(int n, Ruby *a, NumberTypeE nt) {
+ Ruby delim = SYM(#);
+ for (int i=0; i<n; i++) {
+ if (a[i] == delim) {
+ STACK_ARRAY(int32,v,i);
+ if (i!=0 && TYPE(a[i-1])==T_SYMBOL) nt=NumberTypeE_find(a[--i]);
+ for (int j=0; j<i; j++) v[j] = convert(a[j],(int32*)0);
+ init(new Dim(i,v),nt);
+ CHECK_ALIGN2(this->data,nt);
+ if (a[i] != delim) i++;
+ i++; a+=i; n-=i;
+ goto fill;
+ }
+ }
+ if (n!=0 && TYPE(a[0])==T_SYMBOL) {
+ nt = NumberTypeE_find(a[0]);
+ a++, n--;
+ }
+ init(new Dim(n),nt);
+ CHECK_ALIGN2(this->data,nt);
+ fill:
+ int nn = dim->prod();
+ n = min(n,nn);
+#define FOO(type) { \
+ Pt<type> p = (Pt<type>)*this; \
+ if (n==0) CLEAR(p,nn); \
+ else { \
+ for (int i=0; i<n; i++) NUM(a[i],p[i]); \
+ for (int i=n; i<nn; i+=n) COPY(p+i,p,min(n,nn-i)); }}
+ TYPESWITCH(nt,FOO,)
+#undef FOO
+}
+
+void Grid::init_from_ruby(Ruby x) {
+ if (TYPE(x)==T_ARRAY) {
+ init_from_ruby_list(rb_ary_len(x),rb_ary_ptr(x));
+ } else if (INTEGER_P(x) || FLOAT_P(x)) {
+ init(new Dim(),int32_e);
+ CHECK_ALIGN2(this->data,nt);
+ ((Pt<int32>)*this)[0] = INT(x);
+ } else {
+ rb_funcall(
+ EVAL("proc{|x| raise \"can't convert to grid: #{x.inspect}\"}"),
+ SI(call),1,x);
+ }
+}
+
+// **************** GridInlet *************************************
+
+// must be set before the end of GRID_BEGIN phase, and so cannot be changed
+// afterwards. This is to allow some optimisations. Anyway there is no good reason
+// why this would be changed afterwards.
+void GridInlet::set_factor(int factor) {
+ if(!dim) RAISE("huh?");
+ if(factor<=0) RAISE("%s: factor=%d should be >= 1",INFO(parent),factor);
+ if (dim->prod() && dim->prod() % factor)
+ RAISE("%s: set_factor: expecting divisor",INFO(parent));
+ if (factor > 1) {
+ buf=new Grid(new Dim(factor), nt);
+ bufi=0;
+ } else {
+ buf=0;
+ }
+}
+
+static Ruby GridInlet_begin_1(GridInlet *self) {
+#define FOO(T) self->gh->flow(self,-1,Pt<T>()); break;
+ TYPESWITCH(self->nt,FOO,)
+#undef FOO
+ return Qnil;
+}
+
+static Ruby GridInlet_begin_2(GridInlet *self) {
+ self->dim = 0; // hack
+ return (Ruby) 0;
+}
+
+bool GridInlet::supports_type(NumberTypeE nt) {
+#define FOO(T) return !! gh->flow_##T;
+ TYPESWITCH(nt,FOO,return false)
+#undef FOO
+}
+
+Ruby GridInlet::begin(int argc, Ruby *argv) {TRACE;
+ if (!argc) return PTR2FIX(this);
+ GridOutlet *back_out = (GridOutlet *) Pointer_gut(argv[0]);
+ nt = (NumberTypeE) INT(argv[1]);
+ argc-=2, argv+=2;
+ PROF(parent) {
+ if (dim) {
+ gfpost("%s: grid inlet conflict; aborting %s in favour of %s",
+ INFO(parent), INFO(sender), INFO(back_out->parent));
+ abort();
+ }
+ sender = back_out->parent;
+ if ((int)nt<0 || (int)nt>=(int)number_type_table_end)
+ RAISE("%s: inlet: unknown number type",INFO(parent));
+ if (!supports_type(nt))
+ RAISE("%s: number type %s not supported here",
+ INFO(parent), number_type_table[nt].name);
+ STACK_ARRAY(int32,v,argc);
+ for (int i=0; i<argc; i++) v[i] = NUM2INT(argv[i]);
+ P<Dim> dim = this->dim = new Dim(argc,v);
+ dex=0;
+ buf=0;
+ int r = rb_ensure(
+ (RMethod)GridInlet_begin_1,(Ruby)this,
+ (RMethod)GridInlet_begin_2,(Ruby)this);
+ if (!r) {abort(); goto hell;}
+ this->dim = dim;
+ back_out->callback(this);
+ hell:;} // PROF
+ return Qnil;
+}
+
+template <class T> void GridInlet::flow(int mode, int n, Pt<T> data) {TRACE;
+ CHECK_BUSY(inlet);
+ CHECK_TYPE(*data);
+ CHECK_ALIGN(data);
+ PROF(parent) {
+ if (this->mode==0) {dex += n; return;} // ignore data
+ if (n==0) return; // no data
+ switch(mode) {
+ case 4:{
+ int d = dex + bufi;
+ if (d+n > dim->prod()) {
+ gfpost("grid input overflow: %d of %d from [%s] to [%s]",
+ d+n, dim->prod(), INFO(sender), 0);
+ n = dim->prod() - d;
+ if (n<=0) return;
+ }
+ int bufn = factor();
+ if (buf && bufi) {
+ Pt<T> bufd = (Pt<T>)*buf;
+ int k = min(n,bufn-bufi);
+ COPY(bufd+bufi,data,k);
+ bufi+=k; data+=k; n-=k;
+ if (bufi==bufn) {
+ int newdex = dex+bufn;
+ if (this->mode==6) {
+ Pt<T> data2 = ARRAY_NEW(T,bufn);
+ COPY(data2,bufd,bufn);
+ CHECK_ALIGN(data2);
+ gh->flow(this,bufn,data2);
+ } else {
+ CHECK_ALIGN(bufd);
+ gh->flow(this,bufn,bufd);
+ }
+ dex = newdex;
+ bufi = 0;
+ }
+ }
+ int m = (n/bufn)*bufn;
+ if (m) {
+ int newdex = dex + m;
+ if (this->mode==6) {
+ Pt<T> data2 = ARRAY_NEW(T,m);
+ COPY(data2,data,m);
+ CHECK_ALIGN(data2);
+ gh->flow(this,m,data2);
+ } else {
+ gh->flow(this,m,data);
+ }
+ dex = newdex;
+ }
+ data += m;
+ n -= m;
+ if (buf && n>0) COPY((Pt<T>)*buf+bufi,data,n), bufi+=n;
+ }break;
+ case 6:{
+ assert(!buf);
+ int newdex = dex + n;
+ gh->flow(this,n,data);
+ if (this->mode==4) delete[] (T *)data;
+ dex = newdex;
+ }break;
+ case 0: break; // ignore data
+ default: RAISE("%s: unknown inlet mode",INFO(parent));
+ }} // PROF
+}
+
+void GridInlet::end() {TRACE;
+ assert(this);
+ if (!dim) RAISE("%s: inlet not busy",INFO(parent));
+ if (dim->prod() != dex) {
+ gfpost("incomplete grid: %d of %d from [%s] to [%s]",
+ dex, dim->prod(), INFO(sender), INFO(parent));
+ }
+ PROF(parent) {
+#define FOO(T) gh->flow(this,-2,Pt<T>());
+ TYPESWITCH(nt,FOO,)
+#undef FOO
+ } // PROF
+ dim=0;
+ buf=0;
+ dex=0;
+}
+
+template <class T> void GridInlet::from_grid2(Grid *g, T foo) {TRACE;
+ nt = g->nt;
+ dim = g->dim;
+ int n = g->dim->prod();
+ gh->flow(this,-1,Pt<T>());
+ if (n>0 && this->mode!=0) {
+ Pt<T> data = (Pt<T>)*g;
+ CHECK_ALIGN(data);
+ int size = g->dim->prod();
+ if (this->mode==6) {
+ Pt<T> d = data;
+ data = ARRAY_NEW(T,size); // problem with int64,float64 here.
+ COPY(data,d,size);
+ CHECK_ALIGN(data);
+ gh->flow(this,n,data);
+ } else {
+ int ntsz = number_type_table[nt].size;
+ int m = GridOutlet::MAX_PACKET_SIZE/*/ntsz*//factor();
+ if (!m) m++;
+ m *= factor();
+ while (n) {
+ if (m>n) m=n;
+ CHECK_ALIGN(data);
+ gh->flow(this,m,data);
+ data+=m; n-=m; dex+=m;
+ }
+ }
+ }
+ gh->flow(this,-2,Pt<T>());
+ //!@#$ add error handling.
+ // rescue; abort(); end ???
+ dim = 0;
+ dex = 0;
+}
+
+void GridInlet::from_grid(Grid *g) {TRACE;
+ if (!supports_type(g->nt))
+ RAISE("%s: number type %s not supported here",
+ INFO(parent), number_type_table[g->nt].name);
+#define FOO(T) from_grid2(g,(T)0);
+ TYPESWITCH(g->nt,FOO,)
+#undef FOO
+}
+
+/* **************** GridOutlet ************************************ */
+
+void GridOutlet::begin(int woutlet, P<Dim> dim, NumberTypeE nt) {TRACE;
+ int n = dim->count();
+ this->nt = nt;
+ this->dim = dim;
+ Ruby a[n+4];
+ a[0] = INT2NUM(woutlet);
+ a[1] = bsym._grid;
+ a[2] = Pointer_s_noo(this);
+ a[3] = INT2NUM(nt);
+ for(int i=0; i<n; i++) a[4+i] = INT2NUM(dim->get(i));
+ parent->send_out(COUNT(a),a);
+ frozen=true;
+ if (!dim->prod()) {end(); return;}
+ int32 lcm_factor = 1;
+ for (uint32 i=0; i<inlets.size(); i++) lcm_factor = lcm(lcm_factor,inlets[i]->factor());
+ if (nt != buf->nt) {
+ // biggest packet size divisible by lcm_factor
+ int32 v = (MAX_PACKET_SIZE/lcm_factor)*lcm_factor;
+ if (v==0) v=MAX_PACKET_SIZE; // factor too big. don't have a choice.
+ buf=new Grid(new Dim(v),nt);
+ }
+}
+
+// send modifies dex; send_direct doesn't
+template <class T>
+void GridOutlet::send_direct(int n, Pt<T> data) {TRACE;
+ assert(data); assert(frozen);
+ CHECK_BUSY(outlet); CHECK_TYPE(*data); CHECK_ALIGN(data);
+ for (; n>0; ) {
+ int pn = min(n,MAX_PACKET_SIZE);
+ for (uint32 i=0; i<inlets.size(); i++) inlets[i]->flow(4,pn,data);
+ data+=pn, n-=pn;
+ }
+}
+
+void GridOutlet::flush() {TRACE;
+ if (!bufi) return;
+#define FOO(T) send_direct(bufi,(Pt<T>)*buf);
+ TYPESWITCH(buf->nt,FOO,)
+#undef FOO
+ bufi = 0;
+}
+
+template <class T, class S>
+static void convert_number_type(int n, Pt<T> out, Pt<S> in) {
+ for (int i=0; i<n; i++) out[i]=(T)in[i];
+}
+
+//!@#$ buffering in outlet still is 8x faster...?
+//!@#$ should use BitPacking for conversion...?
+// send modifies dex; send_direct doesn't
+template <class T>
+void GridOutlet::send(int n, Pt<T> data) {TRACE;
+ assert(data); assert(frozen);
+ if (!n) return;
+ CHECK_BUSY(outlet); CHECK_ALIGN(data);
+ if (NumberTypeE_type_of(*data)!=nt) {
+ int bs = MAX_PACKET_SIZE;
+#define FOO(T) { \
+ STACK_ARRAY(T,data2,bs); \
+ for (;n>=bs;n-=bs,data+=bs) { \
+ convert_number_type(bs,data2,data); send(bs,data2);} \
+ convert_number_type(n,data2,data); \
+ send(n,data2); }
+ TYPESWITCH(nt,FOO,)
+#undef FOO
+ } else {
+ dex += n;
+ assert(dex <= dim->prod());
+ if (n > MIN_PACKET_SIZE || bufi + n > MAX_PACKET_SIZE) flush();
+ if (n > MIN_PACKET_SIZE) {
+ send_direct(n,data);
+ } else {
+ COPY((Pt<T>)*buf+bufi,data,n);
+ bufi += n;
+ }
+ if (dex==dim->prod()) end();
+ }
+}
+
+template <class T>
+void GridOutlet::give(int n, Pt<T> data) {TRACE;
+ assert(data); CHECK_BUSY(outlet); assert(frozen);
+ assert(dex+n <= dim->prod()); CHECK_ALIGN(data);
+ if (NumberTypeE_type_of(*data)!=nt) {
+ send(n,data);
+ delete[] (T *)data;
+ return;
+ }
+ if (inlets.size()==1 && inlets[0]->mode == 6) {
+ // this is the copyless buffer passing
+ flush();
+ inlets[0]->flow(6,n,data);
+ dex += n;
+ } else {
+ flush();
+ send_direct(n,data);
+ dex += n;
+ delete[] (T *)data;
+ }
+ if (dex==dim->prod()) end();
+}
+
+void GridOutlet::callback(GridInlet *in) {TRACE;
+ CHECK_BUSY(outlet); assert(!frozen);
+ int mode = in->mode;
+ assert(mode==6 || mode==4 || mode==0);
+ inlets.push_back(in);
+}
+
+\class GridObject < FObject
+
+//!@#$ does not handle types properly
+//!@#$ most possibly a big hack
+template <class T>
+void GridObject_r_flow(GridInlet *in, int n, Pt<T> data) {
+ GridObject *self = in->parent;
+ uint32 i;
+ for (i=0; i<self->in.size(); i++) if (in==self->in[i].p) break;
+ if (i==self->in.size()) RAISE("inlet not found?");
+ if (n==-1) {
+ rb_funcall(self->rself,SI(send_in),2,INT2NUM(i),SYM(rgrid_begin));
+ } else if (n>=0) {
+ Ruby buf = rb_str_new((char *)((uint8 *)data),n*sizeof(T));
+ rb_funcall(self->rself,SI(send_in),3,INT2NUM(i),SYM(rgrid_flow),buf);
+ } else {
+ rb_funcall(self->rself,SI(send_in),2,INT2NUM(i),SYM(rgrid_end));
+ }
+}
+
+\def Symbol inlet_nt (int inln) {
+ if (inln<0 || inln>=(int)in.size()) RAISE("bad inlet number");
+ P<GridInlet> inl = in[inln];
+ if (!inl) RAISE("no such inlet #%d",inln);
+ if (!inl->dim) return Qnil;
+ return number_type_table[inl->nt].sym;
+}
+
+\def Array inlet_dim (int inln) {
+ if (inln<0 || inln>=(int)in.size()) RAISE("bad inlet number");
+ P<GridInlet> inl = in[inln];
+ if (!inl) RAISE("no such inlet #%d",inln);
+ if (!inl->dim) return Qnil;
+ int n=inl->dim->count();
+ Ruby a = rb_ary_new2(n);
+ for(int i=0; i<n; i++) rb_ary_push(a,INT2NUM(inl->dim->v[i]));
+ return a;
+}
+
+\def void inlet_set_factor (int inln, int factor) {
+ if (inln<0 || inln>=(int)in.size()) RAISE("bad inlet number");
+ P<GridInlet> inl = in[inln];
+ if (!inl) RAISE("no such inlet #%d",inln);
+ if (!inl->dim) RAISE("inlet #%d not active",inln);
+ inl->set_factor(factor);
+}
+
+\def void send_out_grid_begin (int outlet, Array buf, NumberTypeE nt=int32_e) {
+ if (outlet<0) RAISE("bad outlet number");
+ int n = rb_ary_len(buf);
+ Ruby *p = rb_ary_ptr(buf);
+ STACK_ARRAY(int32,v,n);
+ for (int i=0; i<n; i++) v[i] = convert(p[i],(int32*)0);
+ out = new GridOutlet(this,outlet,new Dim(n,v),nt); // valgrind says leak?
+}
+
+template <class T>
+void send_out_grid_flow_2(P<GridOutlet> go, Ruby s, T bogus) {
+ int n = rb_str_len(s) / sizeof(T);
+ Pt<T> p = rb_str_pt(s,T);
+ go->send(n,p);
+}
+
+\def void send_out_grid_flow (int outlet, String buf, NumberTypeE nt=int32_e) {
+ if (outlet<0) RAISE("bad outlet number");
+#define FOO(T) send_out_grid_flow_2(out,argv[1],(T)0);
+ TYPESWITCH(nt,FOO,)
+#undef FOO
+}
+
+// install_rgrid(Integer inlet, Boolean multi_type? = true)
+static Ruby GridObject_s_install_rgrid(int argc, Ruby *argv, Ruby rself) {
+ if (argc<1 || argc>2) RAISE("er...");
+ IEVAL(rself,"@handlers||=[]");
+ Ruby handlers = rb_ivar_get(rself,SI(@handlers));
+ GridHandler *gh = new GridHandler;
+ bool mt = argc>1 ? argv[1]==Qtrue : 0; /* multi_type? */
+ if (mt) {
+#define FOO(S) gh->flow_##S = GridObject_r_flow;
+EACH_NUMBER_TYPE(FOO)
+#undef FOO
+ } else {
+#define FOO(S) gh->flow_##S = 0;
+EACH_NUMBER_TYPE(FOO)
+#undef FOO
+ }
+ gh->flow_int32 = GridObject_r_flow;
+ //IEVAL(rself,"self.class_eval { def _0_grid(*a) ___grid(0,*a) end }");
+ rb_funcall(handlers,SI([]=),2,INT2NUM(INT(argv[0])),PTR2FIX(gh));
+ return Qnil;
+}
+
+static Ruby GridObject_s_instance_methods(int argc, Ruby *argv, Ruby rself) {
+ static const char *names[] = {"grid","list","float"};
+ Ruby list = rb_class_instance_methods(argc,argv,rself);
+ Ruby handlers = rb_ivar_get(rself,SI(@handlers));
+ if (handlers==Qnil) return list;
+ for (int i=0; i<rb_ary_len(handlers); i++) {
+ Ruby ghp = rb_ary_ptr(handlers)[i];
+ if (ghp==Qnil) continue;
+ GridHandler *gh = FIX2PTR(GridHandler,ghp);
+ char buf[256];
+ for (int j=0; j<COUNT(names); j++) {
+ sprintf(buf,"_%d_%s",i,names[j]);
+ rb_ary_push(list,rb_str_new2(buf));
+ }
+ }
+ return list;
+}
+
+// this does auto-conversion of list/float to grid
+// this also (will) do grid inputs for ruby stuff.
+\def Ruby method_missing (...) {
+ {
+ if (argc<1) RAISE("not enough arguments");
+ if (!SYMBOL_P(argv[0])) RAISE("expected symbol");
+ const char *name = rb_sym_name(argv[0]);
+ char *endp;
+ if (*name++!='_') goto hell;
+ int i = strtol(name,&endp,10);
+ if (name==endp) goto hell;
+ if (*endp++!='_') goto hell;
+ if (strcmp(endp,"grid")==0) {
+ Ruby handlers = rb_ivar_get(rb_obj_class(rself),SI(@handlers));
+ if (TYPE(handlers)!=T_ARRAY) {
+ rb_p(handlers);
+ RAISE("gridhandler-list missing (maybe forgot install_rgrid ?)"
+ " while trying to receive on inlet %d",i);
+ }
+ if (i>=rb_ary_len(handlers)) RAISE("BORK");
+ GridHandler *gh = FIX2PTR(GridHandler, rb_ary_ptr(handlers)[i]);
+ if (in.size()<=(uint32)i) in.resize(i+1);
+ if (!in[i]) in[i]=new GridInlet((GridObject *)this,gh);
+ return in[i]->begin(argc-1,argv+1);
+ }
+ // we call the grid method recursively to ask it its GridInlet*
+ // don't do this before checking the missing method is exactly that =)
+ char foo[42];
+ sprintf(foo,"_%d_grid",i);
+ P<GridInlet> inl = FIX2PTR(GridInlet,rb_funcall(rself,rb_intern(foo),0));
+ if (strcmp(endp,"list" )==0) return inl->from_ruby_list(argc-1,argv+1), Qnil;
+ if (strcmp(endp,"float")==0) return inl->from_ruby (argc-1,argv+1), Qnil;
+ }
+ hell: return rb_call_super(argc,argv);
+}
+
+\classinfo {
+ IEVAL(rself,"install 'GridObject',0,0");
+ // define in Ruby-metaclass
+ rb_define_singleton_method(rself,"instance_methods",(RMethod)GridObject_s_instance_methods,-1);
+ rb_define_singleton_method(rself,"install_rgrid",(RMethod)GridObject_s_install_rgrid,-1);
+ rb_enable_super(rb_singleton_class(rself),"instance_methods");
+}
+\end class GridObject
+
+Ruby cGridObject;
+
+void startup_grid () {
+ \startall
+ cGridObject = rb_const_get(mGridFlow,SI(GridObject));
+}
+
+// never call this. this is a hack to make some things work.
+// i'm trying to circumvent either a bug in the compiler or i don't have a clue. :-(
+void make_gimmick () {
+ GridOutlet foo(0,0,0);
+#define FOO(S) foo.give(0,Pt<S>());
+EACH_NUMBER_TYPE(FOO)
+#undef FOO
+}
+