From 91c0003b158e5f0ed9d0677fb136ae8bb6f86ec5 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Mon, 28 Apr 2008 18:10:15 +0000 Subject: this is an old gridflow, and there's already a svn repository at http://gridflow.ca/svn/trunk svn path=/trunk/; revision=9739 --- externals/gridflow/base/grid.h | 1146 ---------------------------------------- 1 file changed, 1146 deletions(-) delete mode 100644 externals/gridflow/base/grid.h (limited to 'externals/gridflow/base/grid.h') diff --git a/externals/gridflow/base/grid.h b/externals/gridflow/base/grid.h deleted file mode 100644 index 9e971b99..00000000 --- a/externals/gridflow/base/grid.h +++ /dev/null @@ -1,1146 +0,0 @@ -/* - $Id: grid.h,v 1.2 2006-03-15 04:37:08 matju Exp $ - - GridFlow - Copyright (c) 2001,2002,2003,2004,2005 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. -*/ - -#ifndef __GF_GRID_H -#define __GF_GRID_H - -// current version number as string literal -#define GF_VERSION "0.8.1" -#define GF_COMPILE_TIME __DATE__ ", " __TIME__ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef __APPLE__ -static inline void *memalign (size_t a, size_t n) {return malloc(n);} -#else -#include -#endif - -extern "C" { -#include -#include -#include -}; - -#ifndef RUBY_H -#error "Can't do anything without ruby.h" -#endif - -#include "../config.h" - -#ifdef __WIN32__ -#define INT winINT -#define random rand -#undef send -#undef close -#define sigjmp_buf jmp_buf -#define siglongjmp longjmp -#endif - -#define BUG(s,args...) {fprintf(stderr,s "\nat: %s\n",args,__PRETTY_FUNCTION__); ::raise(11);} -#define L gfpost("%s:%d in %s",__FILE__,__LINE__,__PRETTY_FUNCTION__); - -#ifdef IS_BRIDGE -#define RAISE(args...) rb_raise(rb_eArgError,args) -#else -#define RAISE(args...) rb_raise0(__FILE__,__LINE__,__PRETTY_FUNCTION__,rb_eArgError,args) -#endif - -// avoid ruby warning -#ifndef rb_enable_super -#define rb_enable_super(a,b) \ - if (RUBY_RELEASE_CODE < 20030716) rb_enable_super(a,b) -#endif - -typedef VALUE Ruby; - -/* undocumented function from Ruby that is one thing we need to fix a very elusive bug -that manifests itself when embedding ruby inside a plugin of another app. This exists -for all versions of Ruby up to now, and I don't know when it gets fixed. */ -extern "C" void Init_stack(VALUE *addr); - -extern "C" { -void rb_raise0( -const char *file, int line, const char *func, VALUE exc, const char *fmt, ...) -__attribute__ ((noreturn)); -}; -#define SI(_sym_) (rb_intern(#_sym_)) -#define SYM(_sym_) (ID2SYM(SI(_sym_))) -#define DGS(_class_) \ - _class_ *self; \ - Data_Get_Struct(rself,_class_,self); \ - self->check_magic(); - -// returns the size of a statically defined array -// warning: does not work with STACK_ARRAY() -#define COUNT(_array_) ((int)(sizeof(_array_) / sizeof((_array_)[0]))) - -static inline long rb_str_len(Ruby s) {return RSTRING(s)->len;} -static inline char *rb_str_ptr(Ruby s) {return RSTRING(s)->ptr;} -static inline long rb_ary_len(Ruby s) {return RARRAY(s)->len;} -static inline Ruby *rb_ary_ptr(Ruby s) {return RARRAY(s)->ptr;} -static inline const char *rb_sym_name(Ruby sym) {return rb_id2name(SYM2ID(sym));} -#define rb_str_pt(s,t) Pt((t*)rb_str_ptr(s),rb_str_len(s)) -#define IEVAL(_self_,s) rb_funcall(_self_,SI(instance_eval),1,rb_str_new2(s)) -#define EVAL(s) rb_eval_string(s) -#define rassert(_p_) if (!(_p_)) RAISE(#_p_); -// because of older versions of Ruby (1.6.?) -#define rb_obj_class(o) rb_funcall((o),SI(class),0) - -#define WATCH(n,ar) { \ - char foo[16*1024], *p=foo; p += sprintf(p,"%s: ",#ar); \ - for (int q=0; q - -#undef assert -#define assert(_expr_) \ - if (!(_expr_)) { \ - fprintf(stderr, "%s:%d: assertion failed: %s is false\n", \ - __FILE__, __LINE__, #_expr_); \ - ::abort(); } - -// disabling assertion checking? -#ifndef HAVE_DEBUG -#undef assert -#define assert(_foo_) -#endif - -#ifdef HAVE_TSC_PROFILING -#define HAVE_PROFILING -#endif - -#ifdef HAVE_PROFILING -#define PROF(_self_) for (GFStackMarker gf_marker(_self_);gf_marker.once();) -#else -#define PROF(_self_) -#endif // HAVE_PROFILING - -static inline Ruby PTR2FIX (const void *ptr) { - long p = (long)ptr; - if ((p&3)!=0) BUG("unaligned pointer: %p\n",ptr); - return LONG2NUM(p>>2); -} -#define FIX2PTR(type,ruby) ((type *)(TO(long,ruby)<<2)) - -//**************************************************************** - -/* int32 was long before, now int, because of amd64 */ -typedef char int8; typedef unsigned char uint8; -typedef short int16; typedef unsigned short uint16; -typedef int int32; typedef unsigned int uint32; -typedef long long int64;typedef unsigned long long uint64; -typedef float float32; -typedef double float64; - -// three-way comparison (T is assumed Comparable) -template static inline T cmp(T a, T b) { return ab; } - -// a remainder function such that div2(a,b)*b+mod(a,b) = a and for which -// mod(a,b) is in [0;b) or (b;0]. in contrast to C-language builtin a%b, -// this one has uniform behaviour around zero. -static inline int mod(int a, int b) { -int c=a%b; c+=b&-(c&&(a<0)^(b<0)); return c;} - -// counterpart of mod(a,b), just like a/b and a%b are counterparts -static inline int div2(int a, int b) { -int c=a<0; return (a/b)-(c&&!!(a%b));} - -static inline int32 gf_abs( int32 a) { return a>0?a:-a; } -static inline int64 gf_abs( int64 a) { return a>0?a:-a; } -static inline float32 gf_abs(float32 a) { return fabs(a); } -static inline float64 gf_abs(float64 a) { return fabs(a); } - -// integer powers in log(b) time. T is assumed Integer -template static inline T ipow(T a, T b) { - for(T r=1;;) {if (b&1) r*=a; b>>=1; if (!b) return r; a*=a;} -} - -// kludge -static inline float32 ipow(float32 a, float32 b) { return pow(a,b); } -static inline float64 ipow(float64 a, float64 b) { return pow(a,b); } - -#undef min -#undef max -// minimum/maximum functions; T is assumed to be Comparable -template static inline T min(T a, T b) { return a static inline T max(T a, T b) { return a>b?a:b; } -//template inline T min(T a, T b) { T c = (a-b)>>31; return (a&c)|(b&~c); } - -// greatest common divisor, by euclid's algorithm -// this runs in log(a+b) number operations -template static T gcd (T a, T b) { - while (b) {T c=mod(a,b); a=b; b=c;} - return a; -} - -// greatest common divisor, the binary algorithm. haven't tried yet. -template static T gcd2 (T a, T b) { - int s=0; - while ((a|b)&1==0) { a>>=1; b>>=1; s++; } - while (a) { - if (a&1==0) a>>=1; - else if (b&1==0) b>>=1; - else {T t=abs(a-b); if (a static inline T lcm (T a, T b) {return a*b/gcd(a,b);} - -// returns the position (0..31) of highest bit set in a word, or 0 if none. -#define Z(N) if ((x>>N)&(((typeof(x))1<>=N; i+=N; } -static int highest_bit(uint8 x) {int i=0; Z(4)Z(2)Z(1)return i;} -static int highest_bit(uint16 x) {int i=0; Z(8)Z(4)Z(2)Z(1)return i;} -static int highest_bit(uint32 x) {int i=0; Z(16)Z(8)Z(4)Z(2)Z(1)return i;} -static int highest_bit(uint64 x) {int i=0;Z(32)Z(16)Z(8)Z(4)Z(2)Z(1)return i;} -#undef Z -// returns the position (0..31) of lowest bit set in a word, or 0 if none. -template static int lowest_bit(T n) { return highest_bit((~n+1)&n); } - -static double drand() { return 1.0*rand()/(RAND_MAX+1.0); } - -// is little-endian -static inline bool is_le() {int x=1; return ((char *)&x)[0];} - -#if defined(HAVE_PENTIUM) -static inline uint64 rdtsc() { - uint64 x; __asm__ volatile (".byte 0x0f, 0x31":"=A"(x)); return x; -} -#elif defined(HAVE_PPC) -static inline uint64 rdtsc() { -#include -#include -/* see AbsoluteToNanoseconds(), Microseconds() -http://www.simdtech.org/apps/group_public/email/altivec/msg01956.html -and mach_absolute_time() and mach_timebase_info(&info), -then ns=(time*info.numer)/info.denom; -and the timebase_info is constant -(double)mach_absolute_time*gTimeBaseToNS*/ -return 0; -} -#else -static inline uint64 rdtsc() {return 0;} -#endif - -#ifdef HAVE_LITE -#define EACH_INT_TYPE(MACRO) MACRO(uint8) MACRO(int16) MACRO(int32) -#define EACH_FLOAT_TYPE(MACRO) -#else -#define EACH_INT_TYPE(MACRO) MACRO(uint8) MACRO(int16) MACRO(int32) MACRO(int64) -#define EACH_FLOAT_TYPE(MACRO) MACRO(float32) MACRO(float64) -#endif -#define EACH_NUMBER_TYPE(MACRO) EACH_INT_TYPE(MACRO) EACH_FLOAT_TYPE(MACRO) MACRO(ruby) - -// note: loop unrolling macros assume N!=0 -// btw this may cause alignment problems when 8 does not divide N -#define UNROLL_8(MACRO,N,PTR,ARGS...) \ - int n__=(-N)&7; PTR-=n__; N+=n__; \ - switch (n__) { start: \ - case 0:MACRO(0); case 1:MACRO(1); case 2:MACRO(2); case 3:MACRO(3); \ - case 4:MACRO(4); case 5:MACRO(5); case 6:MACRO(6); case 7:MACRO(7); \ - PTR+=8; N-=8; ARGS; if (N) goto start; } -#define UNROLL_4(MACRO,N,PTR,ARGS...) \ - int n__=(-N)&3; PTR-=n__; N+=n__; \ - switch (n__) { start: \ - case 0:MACRO(0); case 1:MACRO(1); case 2:MACRO(2); case 3:MACRO(3); \ - PTR+=4; N-=4; ARGS; if (N) goto start; } - -//**************************************************************** -// my own little Ruby <-> C++ layer - -//struct Arg { Ruby a; }; -//struct ArgList { int n; Pt v; }; -static inline bool INTEGER_P(Ruby x) {return FIXNUM_P(x)||TYPE(x)==T_BIGNUM;} -static inline bool FLOAT_P(Ruby x) {return TYPE(x)==T_FLOAT;} -#define INT(x) TO(int32,x) -#define TO(t,x) convert(x,(t*)0) - -// not using NUM2INT because Ruby can convert Symbol to int -// (by compatibility with Ruby 1.4) -static inline int32 convert(Ruby x, int32 *foo) { - if (INTEGER_P(x)) return NUM2INT(x); - if (FLOAT_P(x)) return NUM2INT(rb_funcall(x,SI(round),0)); - RAISE("expected Integer or Float (got %s)", - rb_str_ptr(rb_funcall(x,SI(inspect),0))); -} -static int16 convert(Ruby x, int16 *foo) { - int v = INT(x); - if (v<-0x8000 || v>=0x8000) RAISE("value %d is out of range",v); - return v;} -static uint16 convert(Ruby x, uint16 *foo) { - int v = INT(x); - if (v<0 || v>=0x10000) RAISE("value %d is out of range",v); - return v;} -static bool convert(Ruby x, bool *foo) { - if (x==Qtrue) return true; - if (x==Qfalse) return false; - switch (TYPE(x)) { - case T_FIXNUM: case T_BIGNUM: case T_FLOAT: return !!INT(x); - default: RAISE("can't convert to bool"); - } -} - -#ifdef HAVE_GCC64 -static uint64 convert(Ruby val, uint64 *foo) { return NUM2ULONG(val); } -static int64 convert(Ruby val, int64 *foo) { return NUM2ULONG(val); } -static Ruby gf_ull2num(uint64 val) { return ULONG2NUM(val); } -static Ruby gf_ll2num(uint64 val) { return LONG2NUM(val); } -#else -static uint64 convert(Ruby val, uint64 *foo) { - if (FIXNUM_P(val)) return (uint64)FIX2LONG(val); - if (TYPE(val)!=T_BIGNUM) RAISE("type error"); - uint64 v = (uint64)NUM2UINT(rb_funcall(val,SI(>>),1,INT2FIX(32))) << 32; - return v + NUM2UINT(rb_funcall(val,SI(&),1,UINT2NUM(0xffffffff)));} -static int64 convert(Ruby val, int64 *foo) { - if (FIXNUM_P(val)) return (int64)FIX2LONG(val); - if (TYPE(val)!=T_BIGNUM) RAISE("type error"); - int64 v = (int64)NUM2INT(rb_funcall(val,SI(>>),1,INT2FIX(32))) << 32; - return v + NUM2UINT(rb_funcall(val,SI(&),1,UINT2NUM(0xffffffff)));} -static Ruby gf_ull2num(uint64 val) { - Ruby x = rb_funcall(UINT2NUM((uint32)(val>>32)),SI(<<),1,INT2FIX(32)); - return rb_funcall(x,SI(+),1,UINT2NUM((uint32)val));} -static Ruby gf_ll2num(int64 val) { - Ruby x = rb_funcall( INT2NUM(( int32)(val>>32)),SI(<<),1,INT2FIX(32)); - return rb_funcall(x,SI(+),1,UINT2NUM((uint32)val));} -#endif - -static long convert(Ruby x, long *foo) { - return sizeof(long)==sizeof(int32) ? - convert(x,(int32 *)0) : - convert(x,(int64 *)0); -} - -static float64 convert(Ruby x, float64 *foo) { - if (INTEGER_P(x)) return INT(x); - if (TYPE(x)!=T_FLOAT) RAISE("not a Float"); - return ((RFloat*)x)->value;} -static float32 convert(Ruby x, float32 *foo) { - return (float32) convert(x,(float64 *)0);} -typedef Ruby Symbol, Array, String, Integer; -static Ruby convert(Ruby x, Ruby *bogus) { return x; } -typedef Ruby (*RMethod)(...); /* !@#$ fishy */ - -#define BUILTIN_SYMBOLS(MACRO) \ - MACRO(_grid,"grid") MACRO(_bang,"bang") MACRO(_float,"float") \ - MACRO(_list,"list") MACRO(_sharp,"#") \ - MACRO(iv_outlets,"@outlets") \ - MACRO(iv_ninlets,"@ninlets") \ - MACRO(iv_noutlets,"@noutlets") -extern struct BuiltinSymbols { -#define FOO(_sym_,_str_) Ruby _sym_; -BUILTIN_SYMBOLS(FOO) -#undef FOO -} bsym; - -typedef struct R { - VALUE r; - R() {r=Qnil;} - R(int x) {r=INT2NUM(x);} - R(unsigned x) {r=UINT2NUM(x);} - R(long x) {r=LONG2NUM(x);} - R(unsigned long x) {r=ULONG2NUM(x);} - R(double x) {r=rb_float_new(x);} - R( int64 x) {r= gf_ll2num(x);} - R(uint64 x) {r=gf_ull2num(x);} - operator bool() {return !!INT2NUM(r);} - operator uint8 () {return INT2NUM(r);} - operator int16 () {return INT2NUM(r);} - operator int32 () {return INT2NUM(r);} - operator int64 () {return convert(r,(int64*)0);} - operator float32 () {return convert(r,(float32*)0);} - operator float64 () {return convert(r,(float64*)0);} -#define FOO(As,Op) \ - R &operator As (int x) {r=rb_funcall(r, SI(Op),1,INT2NUM(x)); return *this;} - FOO(+=,+) FOO(-=,-) FOO(*=,*) FOO(/=,/) FOO(%=,%) - FOO(&=,&) FOO(|=,|) FOO(^=,^) FOO(<<=,<<) FOO(>>=,>>) -#undef FOO -// bool operator == (int x) {return rb_funcall(r,SI(==),1,INT2NUM(x));} -#define FOO(Op) \ - R operator Op (R x) {return rb_funcall(r,SI(Op),1,x.r);} \ - R operator Op (int x) {return rb_funcall(r,SI(Op),1,INT2NUM(x));} - FOO(+) FOO(-) FOO(*) FOO(/) FOO(%) - FOO(&) FOO(|) FOO(^) FOO(<<) FOO(>>) - FOO(<) FOO(>) FOO(<=) FOO(>=) FOO(==) FOO(!=) -#undef FOO - static R value(VALUE r) {R x; x.r=r; return x;} -} ruby; - -static R operator -(int a, R b) {return rb_funcall(a,SI(Op),1,INT2NUM(b.r));} - -static inline R ipow(R a, R b) {return R::value(rb_funcall(a.r,SI(**),1,b.r));} -static inline R gf_abs(R a) { return R::value(rb_funcall(a.r,SI(abs),0)); } -static inline R cmp(R a, R b) { return R::value(rb_funcall(a.r,SI(<=>),1,b.r));} - -//**************************************************************** -// hook into pointer manipulation. will help find memory corruption bugs. - -template class Pt { -typedef ptrdiff_t /* and not int nor long */ Z; -public: - T *p; -#ifdef HAVE_DEBUG - T *start; - Z n; - Pt() : p(0), start(0), n(0) {} - Pt(T *q, Z _n) : p(q), start(q), n(_n) {} - Pt(T *q, Z _n, T *_start) : p(q), start(_start), n(_n) {} -#else - Pt() : p(0) {} - Pt(T *q, Z _n, T *_start=0) : p(q) {} -#endif - T &operator *() { return *p; } - Pt operator+=(Z i) { p+=i; return *this; } - Pt operator-=(Z i) { p-=i; return *this; } - Pt operator++( ) { p++; return *this; } - Pt operator--( ) { p--; return *this; } - Pt operator++(int) { Pt f(*this); ++*this; return f; } - Pt operator--(int) { Pt f(*this); --*this; return f; } - T &operator[](Z i) { -#ifdef HAVE_DEBUG_HARDER - if (!(p+i>=start && p+i=start && p=start && q<=start+n)) - BUG("BUFFER OVERFLOW: 0x%08lx...0x%08lx is not all inside 0x%08lx...0x%08lx", - (long)p,(long)q,start,(long)(start+n)); -#endif - } - - Z operator-(Pt x) { return p-x.p; } - operator bool () { return (bool )p; } - operator void *() { return (void *)p; } - operator int8 *() { return (int8 *)p; } - -/* how do i make typecast operators that are not also default conversions??? */ -/* this should be found so i can clean up the following: */ -#define FOO(S) operator S *() { return (S *)p; } -EACH_NUMBER_TYPE(FOO) -#undef FOO -#ifdef HAVE_DEBUG -#define FOO(S) operator Pt() { return Pt((S *)p,n*sizeof(T)/1,(S *)start); } -EACH_NUMBER_TYPE(FOO) -#undef FOO -#else -#define FOO(S) operator Pt() { return Pt((S *)p,0); } -EACH_NUMBER_TYPE(FOO) -#undef FOO -#endif -/* end 0.8 (TESTING) */ - -#ifdef HAVE_DEBUG - template Pt operator+(U x) { return Pt(p+x,n,start); } - template Pt operator-(U x) { return Pt(p-x,n,start); } -#else - template Pt operator+(U x) { return Pt(p+x,0); } - template Pt operator-(U x) { return Pt(p-x,0); } -#endif -}; - -//template class P : Pt {}; -//a reference counting pointer class -template class P { -public: -#define INCR if (p) p->refcount++; -#define DECR if (p) {p->refcount--; if (!p->refcount) delete p;} - T *p; - P() : p(0) {} - P(T *_p) { p = _p; INCR; } - P(const P &_p) { p = _p.p; INCR; } - P &operator =(T * _p) { DECR; p=_p; INCR; return *this; } - P &operator =(P _p) { DECR; p=_p.p; INCR; return *this; } - bool operator ==(P _p) { return p == _p.p; } - bool operator !=(P _p) { return p != _p.p; } - ~P() { DECR; } - bool operator !(){ return !p; } - operator bool() { return !!p; } - T &operator *() { return *p; } - T *operator ->() { return p; } -//#undef INCR -//#undef DECR -}; - -#ifndef IS_BRIDGE -extern "C" void *gfmalloc(size_t n); -extern "C" void gffree(void *p); -// note that C++ (GCC 3.4) now refuses the :: prefix so i removed it in the 4 following lines: -inline void *operator new (size_t n) { return gfmalloc(n); } -inline void *operator new[] (size_t n) { return gfmalloc(n); } -inline void operator delete (void *p) { gffree(p); } -inline void operator delete[] (void *p) { gffree(p); } -#endif - -#define STACK_ARRAY(T,V,N) T V##_foo[N]; Pt V(V##_foo,N); -#define ARRAY_NEW(T,N) (Pt((T *)new T[N],N)) - -void gfmemcopy(uint8 *out, const uint8 *in, int n); -template inline void COPY(Pt dest, Pt src, int n) { - src.will_use(n); dest.will_use(n); - gfmemcopy((uint8*)dest,(const uint8*)src,n*sizeof(T)); -} -template inline void CLEAR(Pt dest, int n) { - dest.will_use(n); - memset(dest,0,n*sizeof(T)); -} -template static void memswap (Pt a, Pt b, int n) { - STACK_ARRAY(T,c,n); COPY(c,a,n); COPY(a,b,n); COPY(b,c,n); -} - -//**************************************************************** -// CObject is the base class for C++ classes that get exported to Ruby. -// BTW: It's quite convenient to have virtual-methods in the base class -// because otherwise the vtable* isn't at the beginning of the object -// and that's pretty confusing to a lot of people, especially when simple -// casting causes a pointer to change its value. -struct CObject { -#define OBJECT_MAGIC 1618033989 - int32 magic; - int32 refcount; - Ruby rself; // point to Ruby peer - CObject() : magic(OBJECT_MAGIC), refcount(0), rself(0) {} - void check_magic () { - if (magic != OBJECT_MAGIC) { - fprintf(stderr,"Object memory corruption! (ask the debugger)\n"); - for (int i=-2; i<=2; i++) - fprintf(stderr,"this[%d]=0x%08x\n",i,((int*)this)[i]); - raise(11); - } - } - virtual ~CObject() { magic = 0xDEADBEEF; } - virtual void mark() {} // not used for now -}; -void CObject_free (void *); - -// you shouldn't use MethodDecl directly (used by source_filter.rb) -struct MethodDecl { const char *selector; RMethod method; }; -void define_many_methods(Ruby rself, int n, MethodDecl *methods); -extern Ruby mGridFlow, cFObject, cGridObject, cFormat; - -//**************************************************************** -// a Dim is a list of dimensions that describe the shape of a grid -\class Dim < CObject -struct Dim : CObject { - static const int MAX_DIM=16; // maximum number of dimensions in a grid - int n; - Pt v; // safe pointer - int32 v2[MAX_DIM]; // real stuff - void check(); // test invariants - Dim(int n, Pt v) { this->v = Pt(v2,MAX_DIM); this->n = n; COPY(this->v,v,n); check();} - Dim(int n, int32 *v) { this->v = Pt(v2,MAX_DIM); this->n = n; COPY(this->v,Pt(v,n),n); check();} - Dim() {v=Pt(v2,MAX_DIM); n=0; check();} - Dim(int a) {v=Pt(v2,MAX_DIM); n=1;v[0]=a; check();} - Dim(int a,int b) {v=Pt(v2,MAX_DIM); n=2;v[0]=a;v[1]=b; check();} - Dim(int a,int b,int c){v=Pt(v2,MAX_DIM); n=3;v[0]=a;v[1]=b;v[2]=c;check();} - int count() {return n;} - int get(int i) { return v[i]; } - int32 prod(int start=0, int end=-1) { - if (end<0) end+=n; - int32 tot=1; - for (int i=start; i<=end; i++) tot *= v[i]; - return tot; - } - char *to_s(); - bool equal(P o) { - if (n!=o->n) return false; - for (int i=0; iv[i]) return false; - return true; - } -}; -\end class Dim - -//**************************************************************** -//BitPacking objects encapsulate optimised loops of conversion -struct BitPacking; -// those are the types of the optimised loops of conversion -// inputs are const -struct Packer { -#define FOO(S) void (*as_##S)(BitPacking *self, int n, Pt in, Pt out); -EACH_INT_TYPE(FOO) -#undef FOO -}; -struct Unpacker { -#define FOO(S) void (*as_##S)(BitPacking *self, int n, Pt in, Pt out); -EACH_INT_TYPE(FOO) -#undef FOO -}; - -\class BitPacking < CObject -struct BitPacking : CObject { - Packer *packer; - Unpacker *unpacker; - unsigned int endian; // 0=big, 1=little, 2=same, 3=different - int bytes; - int size; - uint32 mask[4]; - BitPacking(){::abort();} // don't call, but don't remove. sorry. - BitPacking(int endian, int bytes, int size, uint32 *mask, - Packer *packer=0, Unpacker *unpacker=0); - bool is_le(); - bool eq(BitPacking *o); - \decl void initialize(Ruby foo1, Ruby foo2, Ruby foo3); - \decl String pack2(String ins, String outs=Qnil); - \decl String unpack2(String ins, String outs=Qnil); - \decl String to_s(); -// main entrances to Packers/Unpackers - template void pack( int n, Pt in, Pt out); - template void unpack(int n, Pt in, Pt out); -}; -\end class - -int high_bit(uint32 n); -int low_bit(uint32 n); -void swap32 (int n, Pt data); -void swap16 (int n, Pt data); - -#define NT_UNSIGNED (1<<0) -#define NT_FLOAT (1<<1) -#define NT_UNIMPL (1<<2) -#define NUMBER_TYPE_LIMITS(T,a,b,c) \ - inline T nt_smallest(T *bogus) {return a;} \ - inline T nt_greatest(T *bogus) {return b;} \ - inline T nt_all_ones(T *bogus) {return c;} - -NUMBER_TYPE_LIMITS( uint8,0,255,255) -NUMBER_TYPE_LIMITS( int16,-0x8000,0x7fff,-1) -NUMBER_TYPE_LIMITS( int32,-0x80000000,0x7fffffff,-1) -NUMBER_TYPE_LIMITS( int64,-0x8000000000000000LL,0x7fffffffffffffffLL,-1) -NUMBER_TYPE_LIMITS(float32,-HUGE_VAL,+HUGE_VAL,(RAISE("all_ones"),0)) -NUMBER_TYPE_LIMITS(float64,-HUGE_VAL,+HUGE_VAL,(RAISE("all_ones"),0)) -NUMBER_TYPE_LIMITS( ruby,ruby(-HUGE_VAL),ruby(+HUGE_VAL),(RAISE("all_ones"),0)) - -#ifdef HAVE_LITE -#define NT_NOTLITE NT_UNIMPL -#define NONLITE(x...) -#else -#define NT_NOTLITE 0 -#define NONLITE(x...) x -#endif -#define NUMBER_TYPES(MACRO) \ - MACRO( uint8, 8,NT_UNSIGNED, "u8,b") MACRO( int8, 8,NT_UNIMPL, "i8") \ - MACRO( uint16,16,NT_UNSIGNED|NT_UNIMPL, "u16") MACRO(int16,16,0, "i16,s") \ - MACRO( uint32,32,NT_UNSIGNED|NT_UNIMPL, "u32") MACRO(int32,32,0, "i32,i") \ - MACRO( uint64,64,NT_UNSIGNED|NT_UNIMPL, "u64") MACRO(int64,64,NT_NOTLITE, "i64,l") \ - MACRO(float32,32,NT_NOTLITE|NT_FLOAT, "f32,f") \ - MACRO(float64,64,NT_NOTLITE|NT_FLOAT, "f64,d") \ - MACRO( ruby,sizeof(long),NT_NOTLITE,"r") - -enum NumberTypeE { -#define FOO(_sym_,args...) _sym_##_e, -NUMBER_TYPES(FOO) -#undef FOO - number_type_table_end -}; - -#define FOO(_type_) \ -inline NumberTypeE NumberTypeE_type_of(_type_ &x) { \ - return _type_##_e; } -EACH_NUMBER_TYPE(FOO) -#undef FOO - -\class NumberType < CObject -struct NumberType : CObject { - Ruby /*Symbol*/ sym; - const char *name; - int size; - int flags; - const char *aliases; - NumberTypeE index; - NumberType(const char *name_, int size_, int flags_, const char *aliases_) : - name(name_), size(size_), flags(flags_), aliases(aliases_) {} - \decl Symbol sym_m(); - \decl int size_m(); - \decl int flags_m(); - \decl int index_m(); -}; -\end class - -NumberTypeE NumberTypeE_find (Ruby sym); - -#define TYPESWITCH(T,C,E) switch (T) { \ - case uint8_e: C(uint8) break; case int16_e: C(int16) break; \ - case int32_e: C(int32) break; NONLITE(case int64_e: C(int64) break; \ - case float32_e: C(float32) break; case float64_e: C(float64) break; \ - case ruby_e: C(ruby) break;) \ - default: E; RAISE("type '%s' not available here",number_type_table[T].sym);} -#define TYPESWITCH_JUSTINT(T,C,E) switch (T) { \ - case uint8_e: C(uint8) break; case int16_e: C(int16) break; \ - case int32_e: C(int32) break; NONLITE(case int64_e: C(int64) break;) \ - default: E; RAISE("type '%s' not available here",number_type_table[T].sym);} - -// Numop objects encapsulate optimised loops of simple operations - -enum LeftRight { at_left, at_right }; - -template -struct NumopOn : CObject { - // Function Vectorisations - typedef void (*Map )( int n, T *as, T b ); Map op_map; - typedef void (*Zip )( int n, T *as, T *bs); Zip op_zip; - typedef void (*Fold)(int an, int n, T *as, T *bs); Fold op_fold; - typedef void (*Scan)(int an, int n, T *as, T *bs); Scan op_scan; - // Algebraic Properties (those involving simply numeric types) - typedef bool (*AlgebraicCheck)(T x, LeftRight side); - // neutral: right: forall y {f(x,y)=x}; left: forall x {f(x,y)=y}; - // absorbent: right: exists a forall y {f(x,y)=a}; ... - T (*neutral)(LeftRight); // default neutral: e.g. 0 for addition, 1 for multiplication - AlgebraicCheck is_neutral, is_absorbent; - NumopOn(Map m, Zip z, Fold f, Scan s, T (*neu)(LeftRight), AlgebraicCheck n, AlgebraicCheck a) : - op_map(m), op_zip(z), op_fold(f), op_scan(s), neutral(neu), is_neutral(n), is_absorbent(a) {} - NumopOn() {} - NumopOn(const NumopOn &z) { - op_map = z.op_map; op_zip = z.op_zip; - op_fold = z.op_fold; op_scan = z.op_scan; - is_neutral = z.is_neutral; neutral = z.neutral; - is_absorbent = z.is_absorbent; } -}; - -// semigroup property: associativity: f(a,f(b,c))=f(f(a,b),c) -#define OP_ASSOC (1<<0) -// abelian property: commutativity: f(a,b)=f(b,a) -#define OP_COMM (1<<1) - -\class Numop < CObject -struct Numop : CObject { - Ruby /*Symbol*/ sym; - const char *name; - int flags; -//private: -#define FOO(T) \ - NumopOn on_##T; \ - NumopOn *on(T &foo) { \ - if (!on_##T.op_map) \ - RAISE("operator %s does not support type "#T,rb_sym_name(sym)); \ - return &on_##T;} -EACH_NUMBER_TYPE(FOO) -#undef FOO -//public: - template inline void map(int n, Pt as, T b) { - as.will_use(n); - on(*as)->op_map(n,(T *)as,b);} - template inline void zip(int n, Pt as, Pt bs) { - as.will_use(n); - bs.will_use(n); - on(*as)->op_zip(n,(T *)as,(T *)bs);} - template inline void fold(int an, int n, Pt as, Pt bs) { - as.will_use(an); - bs.will_use(an*n); - typename NumopOn::Fold f = on(*as)->op_fold; - if (!f) RAISE("operator %s does not support fold",rb_sym_name(sym)); - f(an,n,(T *)as,(T *)bs);} - template inline void scan(int an, int n, Pt as, Pt bs) { - as.will_use(an); - bs.will_use(an*n); - typename NumopOn::Scan f = on(*as)->op_scan; - if (!f) RAISE("operator %s does not support scan",rb_sym_name(sym)); - f(an,n,(T *)as,(T *)bs);} - - \decl void map_m (NumberTypeE nt, int n, String as, String b); - \decl void zip_m (NumberTypeE nt, int n, String as, String bs); - \decl void fold_m (NumberTypeE nt, int an, int n, String as, String bs); - \decl void scan_m (NumberTypeE nt, int an, int n, String as, String bs); - - Numop(Ruby /*Symbol*/ sym_, const char *name_, -#define FOO(T) NumopOn op_##T, -EACH_NUMBER_TYPE(FOO) -#undef FOO - int flags_) : sym(sym_), name(name_), flags(flags_) { -#define FOO(T) on_##T = op_##T; -EACH_NUMBER_TYPE(FOO) -#undef FOO - } -}; -\end class - -extern NumberType number_type_table[]; -extern Ruby number_type_dict; // GridFlow.@number_type_dict={} -extern Ruby op_dict; // GridFlow.@op_dict={} - -static inline NumberTypeE convert(Ruby x, NumberTypeE *bogus) { - return NumberTypeE_find(x); -} - -#ifndef IS_BRIDGE -static Numop *convert(Ruby x, Numop **bogus) { - Ruby s = rb_hash_aref(rb_ivar_get(mGridFlow,SI(@op_dict)),x); - if (s==Qnil) RAISE("expected two-input-operator"); - return FIX2PTR(Numop,s); -} -#endif - -// **************************************************************** -\class Grid < CObject -struct Grid : CObject { - P dim; - NumberTypeE nt; - void *data; - Grid(P dim, NumberTypeE nt, bool clear=false) : dim(0), nt(int32_e), data(0) { - if (!dim) RAISE("hell"); - init(dim,nt); - if (clear) {int size = bytes(); CLEAR(Pt((char *)data,size),size);} - } - Grid(Ruby x) : dim(0), nt(int32_e), data(0) { init_from_ruby(x); } - Grid(int n, Ruby *a, NumberTypeE nt=int32_e) : dim(0), nt(int32_e), data(0) { - init_from_ruby_list(n,a,nt); - } - int32 bytes() { return dim->prod()*number_type_table[nt].size/8; } - P to_dim () { return new Dim(dim->prod(),(Pt)*this); } -#define FOO(type) \ - operator type *() { return (type *)data; } \ - operator Pt() { return Pt((type *)data,dim->prod()); } -EACH_NUMBER_TYPE(FOO) -#undef FOO - Grid *dup () { - Grid *foo=new Grid(dim,nt); - memcpy(foo->data,data,bytes()); - return foo; - } - ~Grid() {if (data) free(data);} -private: - void init(P dim, NumberTypeE nt) { - this->dim = dim; - this->nt = nt; - data = 0; - if (dim) data = memalign(16,bytes()+16); - //fprintf(stderr,"rdata=%p data=%p align=%d\n",rdata,data,align); - } - void init_from_ruby(Ruby x); - void init_from_ruby_list(int n, Ruby *a, NumberTypeE nt=int32_e); -}; -\end class Grid - -static inline Grid *convert (Ruby r, Grid **bogus) { - return r ? new Grid(r) : 0; -} - -// DimConstraint interface: -// return if d is acceptable -// else RAISE with proper descriptive message -typedef void (*DimConstraint)(P d); - -struct PtrGrid : public P { - DimConstraint dc; - void constrain(DimConstraint dc_) { dc=dc_; } - P next; - PtrGrid() : P(), dc(0), next(0) {} - PtrGrid(const PtrGrid &_p) : P(), dc(0), next(0) {dc=_p.dc; p=_p.p; INCR;} - PtrGrid &operator =( Grid *_p) {if(dc&&p)dc(_p->dim); DECR; p=_p; INCR; return *this;} - PtrGrid &operator =(P _p) {if(dc&&p)dc(_p->dim); DECR; p=_p.p; INCR; return *this;} - PtrGrid &operator =(PtrGrid _p) {if(dc&&p)dc(_p->dim); DECR; p=_p.p; INCR; return *this;} -}; - -#ifndef IS_BRIDGE -static inline P convert(Ruby x, P *foo) { - Grid *d = convert(x,(Grid **)0); - if (!d) RAISE("urgh"); - if (d->dim->n!=1) RAISE("dimension list must have only one dimension itself"); - return new Dim(d->dim->v[0],(int32 *)(d->data)); -} - -static inline PtrGrid convert(Ruby x, PtrGrid *foo) { - PtrGrid pg; - pg = convert(x,(Grid **)0); - return pg; -} -#endif - -//**************************************************************** -// GridInlet represents a grid-aware inlet - -// four-part macro for defining the behaviour of a gridinlet in a class -// C:Class I:Inlet -#define GRID_INLET(C,I) \ - template void C::grinw_##I (GridInlet *in, int n, Pt data) { \ - ((C*)(in->parent))->grin_##I(in,n,data); } \ - template void C::grin_##I (GridInlet *in, int n, Pt data) { \ - if (n==-1) -#define GRID_ALLOC else if (n==-3) -#define GRID_FLOW else if (n>=0) -#define GRID_FINISH else if (n==-2) -#define GRID_END } - -/* macro for defining a gridinlet's behaviour as just storage (no backstore) */ -// V is a PtrGrid instance-var -#define GRID_INPUT(C,I,V) \ -GRID_INLET(C,I) { V=new Grid(in->dim,NumberTypeE_type_of(*data)); } \ -GRID_FLOW { COPY((Pt)*(V)+in->dex, data, n); } GRID_FINISH - -// macro for defining a gridinlet's behaviour as just storage (with backstore) -// V is a PtrGrid instance-var -#define GRID_INPUT2(C,I,V) \ - GRID_INLET(C,I) { \ - if (is_busy_except(in)) { \ - V.next = new Grid(in->dim,NumberTypeE_type_of(*data)); \ - } else V= new Grid(in->dim,NumberTypeE_type_of(*data)); \ - } GRID_FLOW { \ - COPY(((Pt)*(V.next?V.next.p:&*V.p))+in->dex, data, n); \ - } GRID_FINISH - -typedef struct GridInlet GridInlet; -typedef struct GridHandler { -#define FOO(T) \ - void (*flow_##T)(GridInlet *in, int n, Pt data); \ - void flow(GridInlet *in, int n, Pt data) const { \ - assert(flow_##T); flow_##T(in,n,data); } -EACH_NUMBER_TYPE(FOO) -#undef FOO -} GridHandler; - -typedef struct GridObject GridObject; -\class GridInlet < CObject -struct GridInlet : CObject { - GridObject *parent; - const GridHandler *gh; - GridObject *sender; - P dim; - NumberTypeE nt; - int dex; - PtrGrid buf;// factor-chunk buffer - int bufi; // buffer index: how much of buf is filled - int mode; // 0=ignore; 4=ro; 6=rw - - int allocfactor,allocmin,allocmax,allocn; - Pt alloc; - -// methods - GridInlet(GridObject *parent_, const GridHandler *gh_) : - parent(parent_), gh(gh_), sender(0), - dim(0), nt(int32_e), dex(0), bufi(0), mode(4) {} - ~GridInlet() {} - void set_factor(int factor); - void set_mode(int mode_) { mode=mode_; } - int32 factor() {return buf?buf->dim->prod():1;} - Ruby begin(int argc, Ruby *argv); - - // n=-1 is begin, and n=-2 is _finish_. the name "end" is now used - // as an end-marker for inlet definitions... sorry for the confusion - // GF-0.8: n=-3 is alloc. - template void flow(int mode, int n, Pt data); - void end(); // this one ought to be called finish(). - void from_ruby_list(int argc, Ruby *argv, NumberTypeE nt=int32_e) { - Grid t(argc,argv,nt); from_grid(&t); - } - void from_ruby(int argc, Ruby *argv) { - Grid t(argv[0]); from_grid(&t); - } - void from_grid(Grid *g); - bool supports_type(NumberTypeE nt); -private: - template void from_grid2(Grid *g, T foo); -}; -\end class GridInlet - -//**************************************************************** -// for use by source_filter.rb ONLY (for \grin and \classinfo) - -// C is for class, I for inlet number -// GRIN1 : int32 only -// GRIN4 : all types -// GRIN2 : integers only; no floats (no R either actually) -// GRINF : floats only; no integers -#ifndef HAVE_LITE -#define GRIN(TB,TS,TI,TL,TF,TD,TR) {TB,TS,TI,TL,TF,TD,TR} -#else -#define GRIN(TB,TS,TI,TL,TF,TD,TR) {TB,TS,TI} -#endif // HAVE_LITE - -#define GRIN1(C,I) GRIN(0,0,C::grinw_##I,0,0,0,0) -#define GRIN4(C,I) GRIN(C::grinw_##I,C::grinw_##I,C::grinw_##I,C::grinw_##I,C::grinw_##I,C::grinw_##I,C::grinw_##I) -#define GRIN2(C,I) GRIN(C::grinw_##I,C::grinw_##I,C::grinw_##I,C::grinw_##I,0,0,0) -#define GRINF(C,I) GRIN(0,0,0,0,C::grinw_##I,C::grinw_##I,0) - -struct FClass { // 0.7.8: removed all GridObject-specific stuff. - void *(*allocator)(); // returns a new C++ object - void (*startup)(Ruby rself); // initializer for the Ruby class - const char *name; // C++/Ruby name (not PD name) - int methodsn; MethodDecl *methods; // C++ -> Ruby methods -}; - -//**************************************************************** -// GridOutlet represents a grid-aware outlet -\class GridOutlet < CObject -struct GridOutlet : CObject { -// number of (minimum,maximum) BYTES to send at once -// starting with version 0.8, this is amount of BYTES, not amount of NUMBERS. - static const int MIN_PACKET_SIZE = 1<<8; - static const int MAX_PACKET_SIZE = 1<<12; -// those are set only once - GridObject *parent; // not a P<> because of circular refs - P dim; // dimensions of the grid being sent - NumberTypeE nt; - PtrGrid buf; // temporary buffer - bool frozen; // is the "begin" phase finished? - std::vector inlets; // which inlets are we connected to -// those are updated during transmission - int dex; // how many numbers were already sent in this connection - int bufi; // number of bytes used in the buffer -// methods - GridOutlet(GridObject *parent_, int woutlet, P dim_, NumberTypeE nt_=int32_e) : - parent(parent_), dim(dim_), nt(nt_), frozen(false), dex(0), bufi(0) { - int ntsz = number_type_table[nt].size; - buf=new Grid(new Dim(MAX_PACKET_SIZE/*/ntsz*/), nt); - begin(woutlet,dim,nt); - } - ~GridOutlet() {} - void callback(GridInlet *in); - - // send/send_direct: data belongs to caller, may be stack-allocated, - // receiver doesn't modify the data; in send(), there is buffering; - // in send_direct(), there is not. When switching from buffered to - // unbuffered mode, flush() must be called - template void send(int n, Pt data); - void flush(); // goes with send(); - - // give: data must be dynamically allocated as a whole: the data - // will be deleted eventually, and should not be used by the caller - // beyond the call to give(). - template void give(int n, Pt data); - - // third way to send (upcoming, in GF-0.8.??) is called "ask". - template void ask(int &n, Pt &data, int factor, int min, int max); - -private: - void begin(int woutlet, P dim, NumberTypeE nt=int32_e); - template void send_direct(int n, Pt data); - void end() { - flush(); - for (uint32 i=0; iend(); - dim=0; - } -}; -\end class GridOutlet - -//**************************************************************** - -typedef struct BFObject BFObject; // Pd t_object or something - -// represents objects that have inlets/outlets -\class FObject < CObject -struct FObject : CObject { - BFObject *bself; // point to PD peer - uint64 total_time; - FObject() : bself(0), total_time(0) {} - const char *args() { - Ruby s=rb_funcall(rself,SI(args),0); - if (s==Qnil) return 0; - return rb_str_ptr(s); - } - \decl Ruby total_time_get(); - \decl Ruby total_time_set(Ruby x); - \decl void send_in (...); - \decl void send_out (...); - \decl void delete_m (); -}; -\end class FObject - -\class GridObject < FObject -struct GridObject : FObject { - std::vector > in; - P out; - // Make sure you distinguish #close/#delete, and C++'s delete. The first - // two are quite equivalent and should never make an object "crashable". - // C++'s delete is called by Ruby's garbage collector or by PureData's delete. - GridObject() {} - ~GridObject() {check_magic();} - bool is_busy_except(P gin) { - for (uint32 i=0; idim) return true; - return false; - } - \decl Ruby method_missing(...); - \decl Array inlet_dim(int inln); - \decl Symbol inlet_nt(int inln); - \decl void inlet_set_factor(int inln, int factor); - \decl void send_out_grid_begin(int outlet, Array dim, NumberTypeE nt=int32_e); - \decl void send_out_grid_flow (int outlet, String buf, NumberTypeE nt=int32_e); -}; -\end class GridObject - -uint64 gf_timeofday(); -extern "C" void Init_gridflow (); -void gfpost(const char *fmt, ...); -extern Numop *op_add,*op_sub,*op_mul,*op_div,*op_mod,*op_shl,*op_and,*op_put; - -#define INFO(OBJ) rb_str_ptr(rb_funcall(OBJ->rself,SI(info),0)) -//#define INFO(OBJ) "(bleh)" -#define NOTEMPTY(_a_) if (!(_a_)) RAISE("in [%s], '%s' is empty",INFO(this), #_a_); -#define SAME_TYPE(_a_,_b_) \ - if ((_a_)->nt != (_b_)->nt) RAISE("%s: same type please (%s has %s; %s has %s)", \ - INFO(this), \ - #_a_, number_type_table[(_a_)->nt].name, \ - #_b_, number_type_table[(_b_)->nt].name); -static void SAME_DIM(int n, P a, int ai, P b, int bi) { - if (ai+n > a->n) RAISE("left hand: not enough dimensions"); - if (bi+n > b->n) RAISE("right hand: not enough dimensions"); - for (int i=0; iv[ai+i] != b->v[bi+i]) { - RAISE("mismatch: left dim #%d is %d, right dim #%d is %d", - ai+i, a->v[ai+i], - bi+i, b->v[bi+i]);}}} - -// a stack for the profiler, etc. -#define GF_STACK_MAX 256 -//#define NO_INLINE(decl) decl __attribute__((noinline)) -#define NO_INLINE(decl) decl -struct GFStack { - struct GFStackFrame { - FObject *o; - void *bp; // a pointer into system stack - uint64 time; - }; // sizeof() == 16 (in 32-bit mode) - GFStackFrame s[GF_STACK_MAX]; - int n; - GFStack() { n = 0; } - NO_INLINE(void push (FObject *o)); - NO_INLINE(void pop ()); -}; -extern GFStack gf_stack; -struct GFStackMarker { - int n; - bool flag; - GFStackMarker(FObject *o) { n = gf_stack.n; gf_stack.push(o); flag=true; } - ~GFStackMarker() { while (gf_stack.n != n) gf_stack.pop(); } - bool once () { - if (flag) { flag=false; return true; } else return false; - } -}; - -typedef GridObject Format; - -#endif // __GF_GRID_H -- cgit v1.2.1