aboutsummaryrefslogtreecommitdiff
path: root/cyclone/hammer/prepend.c
diff options
context:
space:
mode:
Diffstat (limited to 'cyclone/hammer/prepend.c')
-rw-r--r--cyclone/hammer/prepend.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/cyclone/hammer/prepend.c b/cyclone/hammer/prepend.c
new file mode 100644
index 0000000..567bb73
--- /dev/null
+++ b/cyclone/hammer/prepend.c
@@ -0,0 +1,258 @@
+/* Copyright (c) 2002-2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "common/loud.h"
+#include "common/grow.h"
+
+#define PREPEND_INISIZE 32 /* LATER rethink */
+#define PREPEND_MAXSIZE 256
+
+typedef struct _prepend
+{
+ t_object x_ob;
+ t_symbol *x_selector;
+ int x_size; /* as allocated */
+ int x_natoms; /* as used */
+ t_atom *x_message;
+ t_atom x_messini[PREPEND_INISIZE];
+ int x_entered;
+ int x_auxsize;
+ t_atom *x_auxbuf;
+} t_prepend;
+
+static t_class *prepend_class;
+
+/* Usually a preallocation method is used, except in special cases of:
+ 1) reentrant output request, or 2) an output request which would cause
+ resizing to more than MAXSIZE (no such limit for a 'set' message).
+ In both special cases, a temporary output buffer is allocated.
+ A separately preallocated output buffer is not used, thus avoiding
+ memcpying of the stored message (a small performance gain when the
+ preallocation method is chosen). Instead, self-invoked 'set'
+ messages are postponed, using an auxiliary buffer.
+*/
+
+static void prepend_dooutput(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (s == &s_float)
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet, av->a_w.w_float);
+ }
+ else if (s == &s_list)
+ outlet_list(((t_object *)x)->ob_outlet, &s_list, ac, av);
+ else if (s)
+ /* CHECKED: 'bang' is prepended -- we cannot do so...
+ ('symbol' cannot be compatible too) */
+ {
+ outlet_anything(((t_object *)x)->ob_outlet, s, ac, av);
+ }
+}
+
+static void prepend_anything(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ int reentered = x->x_entered;
+ int prealloc = !reentered;
+ int ntotal = x->x_natoms + ac;
+ t_atom *buf;
+ x->x_entered = 1;
+ if (s == &s_) s = 0;
+ if (s)
+ ntotal++;
+ if (prealloc && ntotal > x->x_size)
+ {
+ if (ntotal > PREPEND_MAXSIZE)
+ prealloc = 0;
+ else
+ {
+ int nrequested = ntotal;
+ x->x_message = grow_withdata(&nrequested, &x->x_natoms,
+ &x->x_size, x->x_message,
+ PREPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ prealloc = (nrequested == ntotal);
+ }
+ }
+ if (prealloc)
+ {
+ buf = x->x_message + x->x_natoms;
+ if (s)
+ {
+ SETSYMBOL(buf, s);
+ buf++;
+ }
+ if (ac)
+ memcpy(buf, av, ac * sizeof(*buf));
+ prepend_dooutput(x, x->x_selector, ntotal, x->x_message);
+ }
+ else
+ {
+ /* LATER consider using the stack if ntotal <= MAXSTACK */
+ if (buf = getbytes(ntotal * sizeof(*buf)))
+ {
+ t_atom *bp = buf + x->x_natoms;
+ if (x->x_natoms)
+ memcpy(buf, x->x_message, x->x_natoms * sizeof(*buf));
+ if (s)
+ {
+ SETSYMBOL(bp, s);
+ bp++;
+ }
+ if (ac)
+ memcpy(bp, av, ac * sizeof(*bp));
+ prepend_dooutput(x, x->x_selector, ntotal, buf);
+ freebytes(buf, ntotal * sizeof(*buf));
+ }
+ }
+ if (!reentered)
+ {
+ x->x_entered = 0;
+ if (x->x_auxbuf)
+ {
+ if (x->x_auxsize <= x->x_size)
+ {
+ x->x_natoms = x->x_auxsize / 2;
+ memcpy(x->x_message, x->x_auxbuf,
+ x->x_natoms * sizeof(*x->x_message));
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ }
+ else
+ {
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+ x->x_size = x->x_auxsize;
+ x->x_message = x->x_auxbuf;
+ x->x_natoms = x->x_auxsize / 2;
+ }
+ x->x_auxbuf = 0;
+ }
+ }
+}
+
+static void prepend_bang(t_prepend *x)
+{
+ t_atom at;
+ SETSYMBOL(&at, &s_bang); /* CHECKED */
+ prepend_anything(x, 0, 1, &at);
+}
+
+static void prepend_float(t_prepend *x, t_float f)
+{
+ t_atom at;
+ SETFLOAT(&at, f);
+ prepend_anything(x, 0, 1, &at);
+}
+
+static void prepend_symbol(t_prepend *x, t_symbol *s)
+{
+ t_atom at;
+ SETSYMBOL(&at, s);
+ prepend_anything(x, 0, 1, &at);
+}
+
+/* LATER gpointer */
+
+static void prepend_list(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ prepend_anything(x, 0, ac, av);
+}
+
+static void prepend_set(t_prepend *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ int newsize;
+ if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1) x->x_selector = &s_list;
+ else x->x_selector = &s_float;
+ }
+ else if (av->a_type == A_SYMBOL)
+ {
+ x->x_selector = av->a_w.w_symbol;
+ ac--;
+ av++;
+ }
+ else
+ return; /* LATER rethink */
+ newsize = ac * 2;
+ if (x->x_entered)
+ {
+ if (x->x_auxbuf)
+ {
+ loud_warning((t_pd *)x, "'set' message overridden");
+ freebytes(x->x_auxbuf, x->x_auxsize * sizeof(*x->x_auxbuf));
+ x->x_auxsize = 0;
+ }
+ if (x->x_auxbuf = getbytes(newsize * sizeof(*x->x_auxbuf)))
+ {
+ memcpy(x->x_auxbuf, av, ac * sizeof(*x->x_auxbuf));
+ x->x_auxsize = newsize;
+ }
+ }
+ else
+ {
+ t_atom *ap;
+ if (newsize > x->x_size)
+ {
+ int sz = newsize;
+ x->x_message = grow_nodata(&sz, &x->x_size, x->x_message,
+ PREPEND_INISIZE, x->x_messini,
+ sizeof(*x->x_message));
+ if (sz != newsize)
+ ac = sz / 2; /* LATER rethink */
+ }
+ x->x_natoms = ac;
+ ap = x->x_message;
+ while (ac--) *ap++ = *av++;
+ }
+ }
+}
+
+static void prepend_free(t_prepend *x)
+{
+ if (x->x_message != x->x_messini)
+ freebytes(x->x_message, x->x_size * sizeof(*x->x_message));
+}
+
+static void *prepend_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_prepend *x = (t_prepend *)pd_new(prepend_class);
+ x->x_selector = 0;
+ x->x_size = PREPEND_INISIZE;
+ x->x_natoms = 0;
+ x->x_message = x->x_messini;
+ x->x_auxbuf = 0;
+ x->x_entered = 0;
+ if (!ac)
+ {
+ loud_incompatible(prepend_class,
+ "creating an object without an argument");
+ /* CHECKED: this is not compatible -- in max an object without an outlet
+ is created, and there is no warning if loading from a file. */
+ }
+ outlet_new((t_object *)x, &s_anything);
+ prepend_set(x, 0, ac, av);
+ return (x);
+}
+
+void prepend_setup(void)
+{
+ prepend_class = class_new(gensym("prepend"),
+ (t_newmethod)prepend_new,
+ (t_method)prepend_free,
+ sizeof(t_prepend), 0,
+ A_GIMME, 0);
+ class_addbang(prepend_class, prepend_bang);
+ class_addfloat(prepend_class, prepend_float);
+ class_addsymbol(prepend_class, prepend_symbol);
+ class_addlist(prepend_class, prepend_list);
+ class_addanything(prepend_class, prepend_anything);
+ class_addmethod(prepend_class, (t_method)prepend_set,
+ gensym("set"), A_GIMME, 0);
+}