aboutsummaryrefslogtreecommitdiff
path: root/externals/gridflow/gridflow.h
diff options
context:
space:
mode:
Diffstat (limited to 'externals/gridflow/gridflow.h')
-rw-r--r--externals/gridflow/gridflow.h926
1 files changed, 926 insertions, 0 deletions
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 <vector>
+#include <string>
+#include <sstream>
+#include <map>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <math.h>
+#ifdef __APPLE__
+static inline void *memalign (size_t a, size_t n) {return malloc(n);}
+#else
+#include <malloc.h>
+#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<char *>(s))
+#define sys_vgui(FMT,ARGS...) sys_vgui(const_cast<char *>(FMT),ARGS)
+#define sys_gui(s) sys_gui(const_cast<char *>(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 <class T> static inline T cmp(T a, T b) { return a<b ? -1 : a>b; }
+
+// 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 <class T> 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 <class T> static inline T min(T a, T b) {return a<b?a:b;}
+template <class T> static inline T max(T a, T b) {return a>b?a:b;}
+template <class T> static inline T clip(T a, T lower, T upper) {return a<lower?lower:a>upper?upper:a;}
+//template <class T> 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 <class T> 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 <class T> 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<b) b=t; else a=t;}
+ }
+ return b<<s;
+}
+
+// least common multiple; this runs in log(a+b) like gcd.
+template <class T> 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)-1)) { x>>=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 <class T> 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 <stdio.h>
+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; q<n; q++) p += sprintf(p,"%lld ",(long long)ar[q]); \
+ post("%s",foo);}
+
+//****************************************************************
+
+struct FObject;
+struct t_atom2;
+typedef void (*FMethod)(FObject *, int, t_atom2 *);
+typedef std::string string;
+
+#define BUILTIN_SYMBOLS(MACRO) \
+ MACRO(_grid,"grid") MACRO(_bang,"bang") MACRO(_float,"float") \
+ MACRO(_list,"list") MACRO(_sharp,"#") \
+ MACRO(_in,"in") MACRO(_out,"out")
+
+extern struct BuiltinSymbols {
+#define FOO(_sym_,_str_) t_symbol *_sym_;
+BUILTIN_SYMBOLS(FOO)
+#undef FOO
+} bsym;
+
+struct Numop;
+struct Pointer;
+#define INT(x) convert(x,(int32*)0)
+#define TO(T,x) convert(x,(T*)0)
+
+// trick to be able to define methods in t_atom
+struct t_atom2 : t_atom {
+ bool operator == (t_symbol *b) {return this->a_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 <class T> T convert(const t_atom &x, T *foo) {const t_atom2 *xx = (const t_atom2 *)&x; return (T)*xx;}
+
+//****************************************************************
+
+//template <class T> class P : T * {};
+//a reference counting pointer class
+template <class T> 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<T> &_p) {p=_p.p; INCR;}
+ P<T> &operator = (T * _p) {DECR; p=_p; INCR; return *this;}
+ P<T> &operator = (P<T> _p) {DECR; p=_p.p; INCR; return *this;}
+ bool operator == (P<T> _p) {return p==_p.p;}
+ bool operator != (P<T> _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 <class T> inline void COPY(T *dest, T *src, long n) {
+ gfmemcopy((uint8*)dest,(const uint8*)src,n*sizeof(T));
+}
+template <class T> inline void CLEAR(T *dest, long n) {
+ memset(dest,0,n*sizeof(T));
+}
+template <class T> 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<Dim> o) {
+ if (n!=o->n) return false;
+ for (Card i=0; i<n; i++) if (v[i]!=o->v[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 <class T> void pack(long n, T *in, uint8 *out);
+ template <class T> 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 <class T>
+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<T> on_##T; \
+ NumopOn<T> *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 <class T> inline void map(long n, T *as, T b) {
+ on(*as)->map(n,(T *)as,b);}
+ template <class T> inline void zip(long n, T *as, T *bs) {
+ on(*as)->zip(n,(T *)as,(T *)bs);}
+ template <class T> inline void fold(long an, long n, T *as, T *bs) {
+ typename NumopOn<T>::Fold f = on(*as)->fold;
+ if (!f) RAISE("operator %s does not support fold",name);
+ f(an,n,(T *)as,(T *)bs);}
+ template <class T> inline void scan(long an, long n, T *as, T *bs) {
+ typename NumopOn<T>::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<T> 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<string,NumberType *> number_type_dict;
+extern std::map<string,Numop *> op_dict;
+extern std::map<string,Numop *> 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> dim;
+ NumberTypeE nt;
+ void *data;
+ int state; /* 0:borrowing 1:owning -1:expired(TODO) */
+ Grid(P<Dim> 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 <class T> Grid(P<Dim> 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<Dim> 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> 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<Dim> d);
+
+struct PtrGrid : public P<Grid> {
+ DimConstraint dc;
+ void constrain(DimConstraint dc_) { dc=dc_; }
+ P<Grid> next;
+ PtrGrid() : P<Grid>(), dc(0), next(0) {}
+ PtrGrid(const PtrGrid &_p) : P<Grid>(), dc(0), next(0) {dc=_p.dc; p=_p.p; INCR;}
+// PtrGrid( P<Grid> _p) : P<Grid>(), dc(0), next(0) {dc=_p.dc; p=_p.p; INCR;}
+ PtrGrid( Grid *_p) : P<Grid>(), 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<Grid> _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<Dim> convert(const t_atom &x, P<Dim> *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 <class T> void C::grinw_##I (GridInlet *in, long n, T *data) { \
+ ((C*)(in->parent))->grin_##I(in,n,data); } \
+ template <class T> 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> 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 <class T> 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 <class T> 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<string,AttrDecl *> 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> dim; // dimensions of the grid being sent
+ NumberTypeE nt;
+ std::vector<GridInlet *> 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> 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 <class T> 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 <class T> void give(long n, T *data);
+
+ // third way to send (upcoming, in GF-1.1.??) is called "ask".
+ template <class T> 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> dim, NumberTypeE nt=int32_e);
+ template <class T> void send_direct(long n, T *data);
+ void finish() {
+ flush();
+ for (uint32 i=0; i<inlets.size(); i++) inlets[i]->finish();
+ 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<P<GridInlet> > in;
+ P<GridOutlet> out;
+ FObject(BFObject *bself, MESSAGE) : bself(bself) {bself->self = this;}
+ template <class T> void send_out(int outlet, int argc, T *argv) {
+ t_atom foo[argc];
+ for (int i=0; i<argc; i++) SETFLOAT(&foo[i],argv[i]);
+ outlet_list(bself->outlets[outlet],&s_list,argc,foo);
+ }
+ bool is_busy_except(P<GridInlet> gin) {
+ for (uint32 i=0; i<in.size(); i++) if (in[i] && in[i]!=gin && in[i]->dim) 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<Dim> a, int ai, P<Dim> 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; i<n; i++) {
+ if (a->v[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<string> 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<string,FClass *> fclasses;
+int handle_braces(int ac, t_atom *av);
+
+extern FClass ciFObject, ciFormat;
+
+#endif // __GF_GRID_H