From 3fd823abd398d29e87353fa60e70ec6da1633141 Mon Sep 17 00:00:00 2001 From: Albert Graef <aggraef@gmail.com> Date: Mon, 30 Sep 2024 02:51:54 +0200 Subject: [PATCH] Add new and updated list store methods. Backport from https://github.com/pd-l2ork/pd-l2ork/commit/5397ff79. Thanks MovementGH! --- pd/src/x_list.c | 177 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 149 insertions(+), 28 deletions(-) diff --git a/pd/src/x_list.c b/pd/src/x_list.c index 70dbdfd87..2f7c97d37 100644 --- a/pd/src/x_list.c +++ b/pd/src/x_list.c @@ -516,6 +516,32 @@ static void *list_store_new(t_symbol *s, int argc, t_atom *argv) return (x); } +static void list_store_send(t_list_store *x, t_symbol *s) +{ + t_atom *vec; + int n = x->x_alist.l_n; + if (!s->s_thing) + { + pd_error(x, "%s: no such object", s->s_name); + return; + } + ATOMS_ALLOCA(vec, n); + if (x->x_alist.l_npointer) + { + t_alist y; + alist_clone(&x->x_alist, &y, 0, n); + alist_toatoms(&y, vec, 0, n); + pd_list(s->s_thing, gensym("list"), n, vec); + alist_clear(&y); + } + else + { + alist_toatoms(&x->x_alist, vec, 0, n); + pd_list(s->s_thing, gensym("list"), n, vec); + } + ATOMS_FREEA(vec, n); +} + static void list_store_list(t_list_store *x, t_symbol *s, int argc, t_atom *argv) { @@ -553,61 +579,131 @@ static void list_store_restore_gpointers(t_list_store *x, int offset, int count) } } -static void list_store_append(t_list_store *x, t_symbol *s, - int argc, t_atom *argv) +static void list_store_doinsert(t_list_store *x, t_symbol *s, + int argc, t_atom *argv, int index) { t_listelem *oldptr = x->x_alist.l_vec; - + /* try to allocate more memory */ if (!(x->x_alist.l_vec = (t_listelem *)resizebytes(x->x_alist.l_vec, (x->x_alist.l_n) * sizeof(*x->x_alist.l_vec), (x->x_alist.l_n + argc) * sizeof(*x->x_alist.l_vec)))) { x->x_alist.l_n = 0; - error("list: out of memory"); + pd_error(0, "list: out of memory"); return; } - - /* fix gpointers if resizebytes() has moved the alist in memory */ + /* fix gpointers in case resizebytes() has moved the alist in memory */ if (x->x_alist.l_vec != oldptr && x->x_alist.l_npointer) - list_store_restore_gpointers(x, 0, x->x_alist.l_n); - - alist_copyin(&x->x_alist, s, argc, argv, x->x_alist.l_n); + list_store_restore_gpointers(&x->x_alist, 0, x->x_alist.l_n); + /* shift existing elements after 'index' to the right */ + if (index < x->x_alist.l_n) + { + memmove(x->x_alist.l_vec + index + argc, x->x_alist.l_vec + index, + (x->x_alist.l_n - index) * sizeof(*x->x_alist.l_vec)); + /* fix gpointers because of memmove() */ + if (x->x_alist.l_npointer) + list_store_restore_gpointers(&x->x_alist, index + argc, x->x_alist.l_n - index); + } + /* finally copy new elements */ + alist_copyin(&x->x_alist, s, argc, argv, index); x->x_alist.l_n += argc; } +static void list_store_insert(t_list_store *x, t_symbol *s, + int argc, t_atom *argv) +{ + if (argc > 1) + { + int index = atom_getfloat(argv); + if (index < 0) + { + pd_error(x, "list_store_insert: index %d out of range", index); + return; + } else if (index > x->x_alist.l_n) + index = x->x_alist.l_n; + list_store_doinsert(x, s, --argc, ++argv, index); + } +} + +static void list_store_append(t_list_store *x, t_symbol *s, + int argc, t_atom *argv) +{ + list_store_doinsert(x, s, argc, argv, x->x_alist.l_n); +} + static void list_store_prepend(t_list_store *x, t_symbol *s, int argc, t_atom *argv) { + list_store_doinsert(x, s, argc, argv, 0); +} + +static void list_store_delete(t_list_store *x, t_floatarg f1, t_floatarg f2) +{ + int i, max, index = (int)f1, n = (int)f2; + t_listelem *oldptr = x->x_alist.l_vec; + if (index < 0 || index >= x->x_alist.l_n) + { + pd_error(x, "list_store_delete: index %d out of range", index); + return; + } + max = x->x_alist.l_n - index; + if (!n) + n = 1; /* default */ + else if (n < 0 || n > max) + n = max; /* till the end of the list */ + + /* unset pointers for elements which are to be deleted */ + if (x->x_alist.l_npointer) + { + t_listelem *vec = x->x_alist.l_vec + index; + for (i = 0; i < n; i++) + { + if (vec[i].l_a.a_type == A_POINTER) + { + gpointer_unset(vec[i].l_a.a_w.w_gpointer); + x->x_alist.l_npointer--; + } + } + } + /* shift elements (after the deleted elements) to the left */ + memmove(x->x_alist.l_vec + index, x->x_alist.l_vec + index + n, + (x->x_alist.l_n - index - n) * sizeof(*x->x_alist.l_vec)); + /* shrink memory */ if (!(x->x_alist.l_vec = (t_listelem *)resizebytes(x->x_alist.l_vec, - (x->x_alist.l_n) * sizeof(*x->x_alist.l_vec), - (x->x_alist.l_n + argc) * sizeof(*x->x_alist.l_vec)))) + (x->x_alist.l_n) * sizeof(*x->x_alist.l_vec), + (x->x_alist.l_n - n) * sizeof(*x->x_alist.l_vec)))) { x->x_alist.l_n = 0; - error("list: out of memory"); + pd_error(0, "list: out of memory"); return; } - - memmove(x->x_alist.l_vec + argc, x->x_alist.l_vec, - x->x_alist.l_n * sizeof(*x->x_alist.l_vec)); - - /* we always have to fix gpointers because of memmove() */ if (x->x_alist.l_npointer) - list_store_restore_gpointers(x, argc, x->x_alist.l_n); - - alist_copyin(&x->x_alist, s, argc, argv, 0); - x->x_alist.l_n += argc; + { + /* fix all gpointers in case resizebytes() has moved the alist in memory */ + if (x->x_alist.l_vec != oldptr) + list_store_restore_gpointers(&x->x_alist, 0, x->x_alist.l_n - n); + else /* only fix gpointers after index (because of of memmove()) */ + list_store_restore_gpointers(&x->x_alist, index, x->x_alist.l_n - index - n); + } + x->x_alist.l_n -= n; } -static void list_store_get(t_list_store *x, float f1, float f2) +static void list_store_get(t_list_store *x, t_floatarg f1, t_floatarg f2) { t_atom *outv; int onset = f1, outc = f2; - if (onset < 0 || outc < 0) + if (!outc) + outc = 1; /* default */ + else if (outc < 0) { - pd_error(x, "list_store_get: negative range (%d %d)", onset, outc); - return; + outc = x->x_alist.l_n - onset; /* till the end of the list */ + if (outc <= 0) /* onset out of range */ + { + outlet_bang(x->x_out2); + return; + } } - if (onset + outc > x->x_alist.l_n) + if (onset < 0 || (onset + outc > x->x_alist.l_n)) { outlet_bang(x->x_out2); return; @@ -629,6 +725,23 @@ static void list_store_get(t_list_store *x, float f1, float f2) ATOMS_FREEA(outv, outc); } +static void list_store_set(t_list_store *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 1) + { + int n, max, onset = atom_getfloat(argv); + if (onset < 0 || onset >= x->x_alist.l_n) + { + pd_error(x, "list_store_set: index %d out of range", onset); + return; + } + argc--; argv++; + max = x->x_alist.l_n - onset; + n = (argc > max) ? max : argc; + alist_copyin(&x->x_alist, s, n, argv, onset); + } +} + static void list_store_free(t_list_store *x) { alist_clear(&x->x_alist); @@ -640,12 +753,20 @@ static void list_store_setup(void) (t_newmethod)list_store_new, (t_method)list_store_free, sizeof(t_list_store), 0, A_GIMME, 0); class_addlist(list_store_class, list_store_list); + class_addmethod(list_store_class, (t_method)list_store_send, + gensym("send"), A_SYMBOL, 0); class_addmethod(list_store_class, (t_method)list_store_append, gensym("append"), A_GIMME, 0); class_addmethod(list_store_class, (t_method)list_store_prepend, gensym("prepend"), A_GIMME, 0); + class_addmethod(list_store_class, (t_method)list_store_insert, + gensym("insert"), A_GIMME, 0); + class_addmethod(list_store_class, (t_method)list_store_delete, + gensym("delete"), A_FLOAT, A_DEFFLOAT, 0); class_addmethod(list_store_class, (t_method)list_store_get, - gensym("get"), A_FLOAT, A_FLOAT, 0); + gensym("get"), A_FLOAT, A_DEFFLOAT, 0); + class_addmethod(list_store_class, (t_method)list_store_set, + gensym("set"), A_GIMME, 0); class_sethelpsymbol(list_store_class, &s_list); } @@ -867,7 +988,7 @@ static void list_tosymbol_setup(void) /* ------------- list ------------------- */ -static void *list_new(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) +void *list_new(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) { if (!argc || argv[0].a_type != A_SYMBOL) newest = list_append_new(s, argc, argv); -- GitLab