From 089475041fe26964d72cb2ebc3559a36ba89a2f2 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 8 Jul 2008 05:56:10 +0000 Subject: trying to import gridflow 0.9.4 svn path=/trunk/; revision=10148 --- externals/gridflow/gridflow.h | 926 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 926 insertions(+) create mode 100644 externals/gridflow/gridflow.h (limited to 'externals/gridflow/gridflow.h') diff --git a/externals/gridflow/gridflow.h b/externals/gridflow/gridflow.h new file mode 100644 index 00000000..85eeefd2 --- /dev/null +++ b/externals/gridflow/gridflow.h @@ -0,0 +1,926 @@ +/* + $Id$ + + GridFlow + Copyright (c) 2001-2007 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 __GRIDFLOW_H +#define __GRIDFLOW_H + +#define GF_VERSION "0.9.4" + +#include "m_pd.h" +#include "config.h" +#include +#include +#include +#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 + +#ifndef a_float +#define a_float a_w.w_float +#define a_symbol a_w.w_symbol +#define a_gpointer a_w.w_gpointer +#endif + +#define gensym(s) gensym(const_cast(s)) +#define sys_vgui(FMT,ARGS...) sys_vgui(const_cast(FMT),ARGS) +#define sys_gui(s) sys_gui(const_cast(s)); + +#ifndef DESIREDATA +#define A_LIST t_atomtype(13) /* (t_binbuf *) */ +#endif +// the use of w_gpointer here is fake, just because there's no suitable member in the union +static inline void SETLIST(t_atom *a, t_binbuf *b) {a->a_type = A_LIST; a->a_gpointer = (t_gpointer *)b;} +static inline void SETNULL(t_atom *a) {a->a_type = A_NULL; a->a_gpointer = 0;} + +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, +// that is, the same as around any other whole number. +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) {return (a/b)-((a<0)&&!!(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) {T r=1; for(;;) {if (b&1) r*=a; b>>=1; if (!b) return r; a*=a;}} +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 static inline T clip(T a, T lower, T upper) {return aupper?upper:a;} +//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..63) 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..63) 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];} + +static inline uint64 rdtsc() +#if defined(HAVE_PENTIUM) +{uint64 x; __asm__ volatile (".byte 0x0f, 0x31":"=A"(x)); return x;} +#else +{return 0;} +#endif + +#ifdef HAVE_LITE +#define EACH_INT_TYPE(MACRO) MACRO(uint8) MACRO(int16) MACRO(int32) +#define EACH_FLOAT_TYPE(MACRO) MACRO(float32) +#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) + +// 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; } + +struct Barf { + char *text; + Barf(const char *s, ...); + Barf(const char *file, int line, const char *func, const char *s, ...); + ~Barf() {free(text);} +}; + +#include +extern "C" void *gfmalloc(size_t n); +extern "C" void gffree(void *p); +#if __GNUC__<4 +#define ALLOCPREFIX static inline +#else +#define ALLOCPREFIX inline +#endif +#include "base/new.h" +ALLOCPREFIX void *operator new (size_t n) throw (std::bad_alloc) {return gfmalloc(n);} +ALLOCPREFIX void *operator new[] (size_t n) throw (std::bad_alloc) {return gfmalloc(n);} +ALLOCPREFIX void *operator new (size_t n, const std::nothrow_t&) throw () {return gfmalloc(n);} +ALLOCPREFIX void *operator new[] (size_t n, const std::nothrow_t&) throw () {return gfmalloc(n);} +ALLOCPREFIX void operator delete (void*p) throw() {gffree(p);} +ALLOCPREFIX void operator delete[](void*p) throw() {gffree(p);} +ALLOCPREFIX void operator delete (void*p, const std::nothrow_t&) throw() {gffree(p);} +ALLOCPREFIX void operator delete[](void*p, const std::nothrow_t&) throw() {gffree(p);} + +#define NEWBUF(T,N) (new T[N]) +#define DELBUF(A) (delete[] A) + +#ifdef __WIN32__ +#define INT winINT +#define random rand +#undef send +#undef close +#define sigjmp_buf jmp_buf +#define siglongjmp longjmp +#endif + +//#define _L_ post("%s:%d in %s",__FILE__,__LINE__,__PRETTY_FUNCTION__); +#define _L_ fprintf(stderr,"%s:%d in %s\n",__FILE__,__LINE__,__PRETTY_FUNCTION__); +#define RAISE(args...) throw Barf(__FILE__,__LINE__,__PRETTY_FUNCTION__,args) +#define VA int argc, t_atom2 *argv +// returns the size of a statically defined array +#define COUNT(_array_) ((int)(sizeof(_array_) / sizeof((_array_)[0]))) +#define WATCH(n,ar) { \ + char foo[16*1024], *p=foo; p += sprintf(p,"%s: ",#ar); \ + for (int q=0; qa_type==A_SYMBOL && this->a_symbol==b;} + bool operator != (t_symbol *b) {return !(*this==b);} + operator float32 () const { + if (a_type!=A_FLOAT) RAISE("expected float"); + return a_float;} + operator bool () const {float f = round(float32(*this)); + if (f<0 || f>=2) RAISE("value %f is out of range",f); + return (bool)f;} + operator uint8 () const {float f = round(float32(*this)); + if (f<0 || f>=0x100) RAISE("value %f is out of range",f); + return (uint8)f;} + operator int16 () const {float f = round(float32(*this)); + if (f<-0x8000 || f>=0x8000) RAISE("value %f is out of range",f); + return (int16)f;} + operator uint16 () const {float f = round(float32(*this)); + if (f<0 || f>=0x10000) RAISE("value %f is out of range",f); + return (uint16)f;} + operator int32 () const {float f = round(float32(*this)); + if (f<-0x80000000LL || f>=0x80000000LL) RAISE("value %f is out of range",f); + return (int32)f;} + operator uint32 () const {float f = round(float32(*this)); + if (f<0 || f>=0x100000000LL) RAISE("value %f is out of range",f); + return (uint32)f;} + operator long () const { + return sizeof(long)==sizeof(int32) ? (int32)*this : (int64)*this;} + operator uint64 () const { + if (a_type!=A_FLOAT) RAISE("expected float"); + return (uint64)round(a_float);} + operator int64 () const { + if (a_type!=A_FLOAT) RAISE("expected float"); + return (int64)round(a_float);} + operator float64 () const { + if (a_type!=A_FLOAT) RAISE("expected float"); + return a_float;} + operator t_symbol * () const { + if (a_type!=A_SYMBOL) RAISE("expected symbol"); + return a_symbol;} + operator std::string () const { + if (a_type!=A_SYMBOL) RAISE("expected symbol"); + return std::string(a_symbol->s_name);} + operator void * () const { + if (a_type!=A_POINTER) RAISE("expected pointer"); + return a_gpointer;} + operator t_binbuf * () const { + if (a_type!=A_LIST) RAISE("expected nested list"); + return (t_binbuf *)a_gpointer;} +}; + +template T convert(const t_atom &x, T *foo) {const t_atom2 *xx = (const t_atom2 *)&x; return (T)*xx;} + +//**************************************************************** + +//template class P : T * {}; +//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;} + operator T *() {return p;} +//#undef INCR +//#undef DECR +}; + +void gfmemcopy(uint8 *out, const uint8 *in, long n); +template inline void COPY(T *dest, T *src, long n) { + gfmemcopy((uint8*)dest,(const uint8*)src,n*sizeof(T)); +} +template inline void CLEAR(T *dest, long n) { + memset(dest,0,n*sizeof(T)); +} +template static void memswap (T *a, T *b, long n) { + T c[n]; COPY(c,a,n); COPY(a,b,n); COPY(b,c,n); +} + +//**************************************************************** + +struct CObject { + int32 refcount; + CObject() : refcount(0) {} + virtual ~CObject() {} + virtual void changed (t_symbol *s=0) {} +}; + +// you shouldn't use MethodDecl directly (used by source_filter.rb) +struct MethodDecl {const char *selector; FMethod method;}; + +#undef check + +//**************************************************************** +// a Dim is a list of dimensions that describe the shape of a grid +typedef int32 Card; /* should be switched to long int soon */ +struct Dim : CObject { + static const Card MAX_DIM=16; // maximum number of dimensions in a grid + Card n; + Card v[MAX_DIM]; // real stuff + void check(); // test invariants + Dim(Card n, Card *v){this->n=n; COPY(this->v,v,n); check();} + Dim() {n=0; check();} + Dim(Card a) {n=1;v[0]=a; check();} + Dim(Card a,Card b) {n=2;v[0]=a;v[1]=b; check();} + Dim(Card a,Card b,Card c){n=3;v[0]=a;v[1]=b;v[2]=c;check();} + Dim(Dim *a, Dim *b, Dim *c=0) { + n=a->n+b->n; if(c) n+=c->n; + if (n>Dim::MAX_DIM) RAISE("too many dims"); + COPY(v ,a->v,a->n); + COPY(v+a->n,b->v,b->n); + if(c) COPY(v+a->n+b->n,c->v,c->n); + } + Card count() {return n;} + Card get(Card i) {return v[i];} +/* Dim *range(Card i, Card j) {return new Dim(...);} */ + Card prod(Card start=0, Card end=-1) { + if (end<0) end+=n; + Card tot=1; + for (Card i=start; i<=end; i++) tot *= v[i]; + return tot; + } + char *to_s(); + bool equal(P o) { + if (n!=o->n) return false; + for (Card i=0; iv[i]) return false; + return true; + } +}; + +//**************************************************************** +//NumberTypeE is a very small int identifying the type of the (smallest) elements of a grid + +#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)) + +#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(int16,16,0, "i16,s") \ + MACRO(int32,32,0, "i32,i") \ + MACRO(int64,64,NT_NOTLITE, "i64,l") \ + MACRO(float32,32,NT_FLOAT, "f32,f") \ + MACRO(float64,64,NT_NOTLITE|NT_FLOAT, "f64,d") + +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 + +struct NumberType : CObject { + 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_) {} +}; + +NumberTypeE NumberTypeE_find (string sym); +NumberTypeE NumberTypeE_find (const t_atom &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; NONLITE(case float64_e: C(float64) break;) \ + default: E; RAISE("type '%s' not available here",number_type_table[T].name);} +#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].name);} + +//**************************************************************** +//BitPacking objects encapsulate optimised loops of bitfield conversion (mostly for I/O) +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, long n, S *in, uint8 *out); +EACH_INT_TYPE(FOO) +#undef FOO +}; +struct Unpacker { +#define FOO(S) void (*as_##S)(BitPacking *self, long n, uint8 *in, S *out); +EACH_INT_TYPE(FOO) +#undef FOO +}; + +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); +// main entrances to Packers/Unpackers + template void pack(long n, T *in, uint8 *out); + template void unpack(long n, uint8 *in, T *out); +}; + +int high_bit(uint32 n); +int low_bit(uint32 n); +void swap16(long n, uint16 *data); +void swap32(long n, uint32 *data); +void swap64(long n, uint64 *data); +inline void swap_endian(long n, uint8 *data) {} +inline void swap_endian(long n, int16 *data) {swap16(n,(uint16 *)data);} +inline void swap_endian(long n, int32 *data) {swap32(n,(uint32 *)data);} +inline void swap_endian(long n, int64 *data) {swap64(n,(uint64 *)data);} +inline void swap_endian(long n, float32 *data) {swap32(n,(uint32 *)data);} +inline void swap_endian(long n, float64 *data) {swap64(n,(uint64 *)data);} + +//**************************************************************** +// Numop objects encapsulate optimised loops of simple operations + +enum LeftRight { at_left, at_right }; + +template +struct NumopOn { + // Function Vectorisations + typedef void (*Map )( long n, T *as, T b ); Map map; + typedef void (*Zip )( long n, T *as, T *bs); Zip zip; + typedef void (*Fold)(long an, long n, T *as, T *bs); Fold fold; + typedef void (*Scan)(long an, long n, T *as, T *bs); Scan 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}; ... + void (*neutral)(T *,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, + void (*neu)(T *,LeftRight), AlgebraicCheck n, AlgebraicCheck a) : + map(m), zip(z), fold(f), scan(s), neutral(neu), is_neutral(n), is_absorbent(a) {} + NumopOn() : map(0),zip(0),fold(0),scan(0),neutral(0),is_neutral(0),is_absorbent(0) {} + NumopOn(const NumopOn &z) { + map=z.map; zip=z.zip; fold=z.fold; scan=z.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) + +struct Numop { + const char *name; + t_symbol *sym; + int flags; + int size; // numop=1; vecop>1 +#define FOO(T) NumopOn on_##T; \ + NumopOn *on(T &foo) { \ + if (!on_##T.map) RAISE("operator %s does not support type "#T,name); \ + return &on_##T;} +EACH_NUMBER_TYPE(FOO) +#undef FOO + template inline void map(long n, T *as, T b) { + on(*as)->map(n,(T *)as,b);} + template inline void zip(long n, T *as, T *bs) { + on(*as)->zip(n,(T *)as,(T *)bs);} + template inline void fold(long an, long n, T *as, T *bs) { + typename NumopOn::Fold f = on(*as)->fold; + if (!f) RAISE("operator %s does not support fold",name); + f(an,n,(T *)as,(T *)bs);} + template inline void scan(long an, long n, T *as, T *bs) { + typename NumopOn::Scan f = on(*as)->scan; + if (!f) RAISE("operator %s does not support scan",name); + f(an,n,(T *)as,(T *)bs);} + + Numop(const char *name_, +#define FOO(T) NumopOn op_##T, +EACH_NUMBER_TYPE(FOO) +#undef FOO + int flags_, int size_) : name(name_), flags(flags_), size(size_) { +#define FOO(T) on_##T = op_##T; +EACH_NUMBER_TYPE(FOO) +#undef FOO + sym=gensym((char *)name); + } +}; + +extern NumberType number_type_table[]; +extern std::map number_type_dict; +extern std::map op_dict; +extern std::map vop_dict; + +static inline NumberTypeE convert(const t_atom &x, NumberTypeE *bogus) { + if (x.a_type!=A_SYMBOL) RAISE("expected number-type"); return NumberTypeE_find(string(x.a_symbol->s_name));} + + +static Numop *convert(const t_atom &x, Numop **bogus) { + if (x.a_type!=A_SYMBOL) RAISE("expected numop (as symbol)"); + string k = string(x.a_symbol->s_name); + if (op_dict.find(k)==op_dict.end()) { + if (vop_dict.find(k)==vop_dict.end()) RAISE("expected two-input-operator, not '%s'", k.data()); + return vop_dict[k]; + } else return op_dict[k]; +} + +// **************************************************************** +struct Grid : CObject { + P dim; + NumberTypeE nt; + void *data; + int state; /* 0:borrowing 1:owning -1:expired(TODO) */ + Grid(P dim, NumberTypeE nt, bool clear=false) { + state=1; + if (!dim) RAISE("hell"); + init(dim,nt); + if (clear) {long size = bytes(); CLEAR((char *)data,size);} + } + Grid(const t_atom &x) {state=1; init_from_atom(x);} + Grid(int n, t_atom *a, NumberTypeE nt_=int32_e) {state=1; init_from_list(n,a,nt_);} + template Grid(P dim, T *data) { + state=0; this->dim=dim; + this->nt=NumberTypeE_type_of((T *)0); + this->data = data; + } + // parens are necessary to prevent overflow at 1/16th of the word size (256 megs) + long bytes() { return dim->prod()*(number_type_table[nt].size/8); } + P to_dim () { return new Dim(dim->prod(),(int32 *)*this); } +#define FOO(T) operator T *() { return (T *)data; } +EACH_NUMBER_TYPE(FOO) +#undef FOO + Grid *dup () { /* always produce an owning grid even if from a borrowing grid */ + Grid *foo=new Grid(dim,nt); + memcpy(foo->data,data,bytes()); + return foo; + } + ~Grid() {if (state==1 && 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); + if (!data) RAISE("out of memory (?) trying to get %ld bytes",bytes()); + } + //fprintf(stderr,"rdata=%p data=%p align=%d\n",rdata,data,align); + } + void init_from_atom(const t_atom &x); + void init_from_list( int n, t_atom *a, NumberTypeE nt=int32_e); +}; +static inline Grid *convert (const t_atom &r, Grid **bogus) {return new Grid(r);} + +// 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( P _p) : P(), dc(0), next(0) {dc=_p.dc; p=_p.p; INCR;} + PtrGrid( Grid *_p) : P(), dc(0), next(0) { + 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;} +}; +#undef INCR +#undef DECR + +static inline P convert(const t_atom &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(const t_atom &x, PtrGrid *foo) {return PtrGrid(convert(x,(Grid **)0));} + +//**************************************************************** +// 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, long n, T *data) { \ + ((C*)(in->parent))->grin_##I(in,n,data); } \ + template void C::grin_##I (GridInlet *in, long n, T *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((T *)*(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(((T *)*(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, long n, T *data); \ + void flow(GridInlet *in, long n, T *data) const {flow_##T(in,n,data);} +EACH_NUMBER_TYPE(FOO) +#undef FOO +} GridHandler; + +struct FObject; +struct GridInlet : CObject { + FObject *parent; + const GridHandler *gh; +private: + FObject *sender; +public: + P dim; + NumberTypeE nt; + long dex; +private: + PtrGrid buf;// factor-chunk buffer + long bufi; // buffer index: how much of buf is filled +public: + int mode; // 0=ignore; 4=ro; 6=rw +// long allocfactor,allocmin,allocmax,allocn; +// uint8 *alloc; + + GridInlet(FObject *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(long factor); // obsolete + void set_chunk(long whichdim); + void set_mode(int mode_) { mode=mode_; } + int32 factor() {return buf?buf->dim->prod():1;} + void begin(int argc, t_atom2 *argv); + void finish(); /* i thought this should be private but maybe it shouldn't. */ + + // n=-1 is begin, and n=-2 is finish; GF-0.9 may have n=-3 meaning alloc (?). + template void flow(int mode, long n, T *data); + void from_list(VA, NumberTypeE nt=int32_e) {Grid t(argc,argv,nt); from_grid(&t);} + void from_atom(VA) {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); +}; + +//**************************************************************** +// for use by source_filter.rb ONLY (for \grin) +#ifndef HAVE_LITE +#define GRIN(TB,TS,TI,TL,TF,TD) {TB,TS,TI,TL,TF,TD} +#else +#define GRIN(TB,TS,TI,TL,TF,TD) {TB,TS,TI,TF} +#endif // HAVE_LITE +#define MESSAGE t_symbol *sel, int argc, t_atom2 *argv +#define MESSAGE2 sel,argc,argv +#define MESSAGE3 t_symbol *, int, t_atom2 * +struct AttrDecl { + string name; + string type; + AttrDecl(string name_, string type_) {name=name_; type=type_;} +}; +struct BFObject; +typedef FObject *(*t_allocator)(BFObject *,MESSAGE3); +struct FClass { + t_allocator allocator; // returns a new C++ object + void (*startup)(FClass *); + const char *cname; // C++ name (not PD name) + int methodsn; MethodDecl *methods; + FClass *super; + int ninlets; + int noutlets; + t_class *bfclass; + string name; + size_t bytes; + std::map attrs; +}; + +void fclass_install(FClass *fc, FClass *super, size_t bytes); + +//**************************************************************** +// GridOutlet represents a grid-aware outlet +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 long MIN_PACKET_SIZE = 1<<8; + static const long MAX_PACKET_SIZE = 1<<12; +// those are set only once + FObject *parent; // not a P<> because of circular refs + P dim; // dimensions of the grid being sent + NumberTypeE nt; + std::vector inlets; // which inlets are we connected to +// those are updated during transmission + long dex; // how many numbers were already sent in this connection + + GridOutlet(FObject *parent_, int woutlet, P dim_, NumberTypeE nt_=int32_e); + ~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(long n, T *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(long n, T *data); + + // third way to send (upcoming, in GF-1.1.??) is called "ask". + template void ask(int &n, T *&data, long factor, long min, long max); + +private: + bool frozen; // is the "begin" phase finished? + PtrGrid buf; // temporary buffer + long bufi; // number of bytes used in the buffer + void begin(int woutlet, P dim, NumberTypeE nt=int32_e); + template void send_direct(long n, T *data); + void finish() { + flush(); + for (uint32 i=0; ifinish(); + dim=0; + } +}; + +//**************************************************************** + +#define CHECK_GRIN(class,i) \ + if (in.size()<=i) in.resize(i+1); \ + if (!in[i]) in[i]=new GridInlet((FObject *)this,&class##_grid_##i##_hand); + +#define CHECK_ALIGN16(d,nt) \ + {int bytes = 16; \ + int align = ((ulong)(void*)d)%bytes; \ + if (align) {_L_;post("%s(%s): Alignment Warning: %s=%p is not %d-aligned: %d", \ + ARGS(this), __PRETTY_FUNCTION__,#d,(void*)d,bytes,align);}} + +struct BFProxy; +struct BFObject : t_object { + void *gemself; // this absolutely needs to be the first field, to make GEM happy + FObject *self; + int ninlets,noutlets; // per object settings (not class) + BFProxy **inlets; // direct access to inlets (not linked lists) + t_outlet **outlets; // direct access to outlets (not linked lists) + t_canvas *mom; + void ninlets_set(int n, bool draw=true); + void noutlets_set(int n, bool draw=true); +}; + +// represents objects that have inlets/outlets +\class FObject : CObject { + BFObject *bself; // point to PD peer + std::vector > in; + P out; + FObject(BFObject *bself, MESSAGE) : bself(bself) {bself->self = this;} + template void send_out(int outlet, int argc, T *argv) { + t_atom foo[argc]; + for (int i=0; ioutlets[outlet],&s_list,argc,foo); + } + bool is_busy_except(P gin) { + for (uint32 i=0; idim) return true; + return false; + } + \decl 0 get (t_symbol *s=0); + \decl 0 help (); +}; +\end class + +uint64 gf_timeofday(); +extern "C" void Init_gridflow (); +extern Numop *op_add,*op_sub,*op_mul,*op_div,*op_mod,*op_shl,*op_and,*op_put; + +#define ARGS(OBJ) "(some object...)" +#define NOTEMPTY(_a_) if (!(_a_)) RAISE("in [%s], '%s' is empty",ARGS(this), #_a_); +#define SAME_TYPE(_a_,_b_) \ + if ((_a_)->nt != (_b_)->nt) RAISE("%s: same type please (%s has %s; %s has %s)", ARGS(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]);}}} + +void suffixes_are (const char *name, const char *suffixes); +#define install(name,inlets,outlets) install2(fclass,name,inlets,outlets) +void install2(FClass *fclass, const char *name, int inlets, int outlets); +#define add_creator(name) add_creator2(fclass,name) +void add_creator2(FClass *fclass, const char *name); +#define install_format(name,mode,suffixes) do {install(name,1,1); suffixes_are(name,suffixes);} while(0) +void call_super(int argc, t_atom *argv); +#define SUPER call_super(argc,argv); + +\class Format : FObject { + int mode; + int fd; + FILE *f; + NumberTypeE cast; + long frame; + Format(BFObject *, MESSAGE); + \decl 0 open (t_symbol *mode, string filename); + \decl 0 close (); + \decl 0 cast (NumberTypeE nt); + \decl 0 seek(int frame); + \decl 0 rewind (); + ~Format (); +}; + +extern std::vector gf_data_path; +string gf_find_file (string x); +void pd_oprintf (std::ostream &o, const char *s, int argc, t_atom *argv); +void pd_oprint (std::ostream &o, int argc, t_atom *argv); +void pd_post (const char *s, int argc, t_atom *argv); + +inline void set_atom (t_atom *a, uint8 v) {SETFLOAT(a,(float)v);} +inline void set_atom (t_atom *a, int16 v) {SETFLOAT(a,(float)v);} +inline void set_atom (t_atom *a, int32 v) {SETFLOAT(a,(float)v);} +inline void set_atom (t_atom *a, uint32 v) {SETFLOAT(a,(float)v);} +inline void set_atom (t_atom *a, long v) {SETFLOAT(a,(float)v);} +inline void set_atom (t_atom *a, float32 v) {SETFLOAT(a,v);} +inline void set_atom (t_atom *a, float64 v) {SETFLOAT(a,v);} +inline void set_atom (t_atom *a, t_symbol *v) {SETSYMBOL(a,v);} +inline void set_atom (t_atom *a, Numop *v) {SETSYMBOL(a,v->sym);} +inline void set_atom (t_atom *a, t_binbuf *v) {SETLIST(a,v);} + +extern std::map fclasses; +int handle_braces(int ac, t_atom *av); + +extern FClass ciFObject, ciFormat; + +#endif // __GF_GRID_H -- cgit v1.2.1