diff options
Diffstat (limited to 'shared')
-rw-r--r-- | shared/common/dict.c | 265 | ||||
-rw-r--r-- | shared/common/dict.h | 27 |
2 files changed, 292 insertions, 0 deletions
diff --git a/shared/common/dict.c b/shared/common/dict.c new file mode 100644 index 0000000..33ee365 --- /dev/null +++ b/shared/common/dict.c @@ -0,0 +1,265 @@ +/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* this is merely an abstraction layer over gensym() from m_class.c + with various additions adapted from m_pd.c */ + +#include <stdio.h> +#include <string.h> +#include "m_pd.h" +#include "common/dict.h" + +#define DICT_VERBOSE +//#define DICT_DEBUG + +#define DICT_HASHSIZE_DEFAULT 1024 +#define DICT_HASHSIZE_MIN 8 +#define DICT_HASHSIZE_MAX 16384 + +/* two structures local to m_pd.c */ +typedef struct _dict_bindelem +{ + t_pd *e_who; + struct _dict_bindelem *e_next; +} t_dict_bindelem; + +typedef struct _dict_bindlist +{ + t_pd b_pd; + t_dict_bindelem *b_list; +} t_dict_bindlist; + +/* adapted bindlist_anything() from m_pd.c */ +static void dict_bindlist_anything(t_dict_bindlist *x, t_symbol *s, + int argc, t_atom *argv) +{ + t_dict_bindelem *e; + for (e = x->b_list; e; e = e->e_next) + pd_typedmess(e->e_who, s, argc, argv); +} + +/* adapted m_pd_setup() from m_pd.c */ +static void dict_bindlist_setup(t_dict *x) +{ + x->d_bindlist_class = class_new(dict_key(x, "bindlist"), 0, 0, + sizeof(t_dict_bindlist), CLASS_PD, 0); + class_addanything(x->d_bindlist_class, dict_bindlist_anything); +} + +t_dict *dict_new(size_t hashsize) +{ + t_dict *x = getbytes(sizeof(*x)); + size_t sz; + if (x) + { + if (!hashsize) + sz = DICT_HASHSIZE_DEFAULT; + else if (hashsize >= DICT_HASHSIZE_MAX) + sz = DICT_HASHSIZE_MAX; + else if (hashsize <= DICT_HASHSIZE_MIN) + sz = DICT_HASHSIZE_MIN; + else for (sz = DICT_HASHSIZE_MAX; sz > DICT_HASHSIZE_MIN; sz >>= 1) + if (sz <= hashsize) break; +#ifdef DICT_DEBUG + post("allocating dictionary with %d-element hashtable", sz); +#endif + if (x->d_hashtable = + getbytes((x->d_hashsize = sz) * sizeof(*x->d_hashtable))) + { + dict_bindlist_setup(x); + return (x); + } + freebytes(x, sizeof(*x)); + } + return (0); +} + +void dict_free(t_dict *x) +{ + if (x->d_hashtable) + freebytes(x->d_hashtable, x->d_hashsize * sizeof(*x->d_hashtable)); + freebytes(x, sizeof(*x)); +} + +/* adapted dogensym() from m_class.c */ +t_symbol *dict_dokey(t_dict *x, char *s, t_symbol *oldsym) +{ + t_symbol **sym1, *sym2; + unsigned int hash1 = 0, hash2 = 0; + int length = 0; + char *s2 = s; + int mask = x->d_hashsize - 1; +#ifdef DICT_DEBUG + startpost("make symbol-key from \"%s\"", s); +#endif + while (*s2) + { + hash1 += *s2; + hash2 += hash1; + length++; + s2++; + } + sym1 = x->d_hashtable + (hash2 & mask); +#ifdef DICT_DEBUG + post(" in slot %d", (hash2 & mask)); +#endif + while (sym2 = *sym1) + { +#ifdef DICT_DEBUG + post("try \"%s\"", sym2->s_name); +#endif + if (!strcmp(sym2->s_name, s)) + { +#ifdef DICT_DEBUG + post("found at address %x", (int)sym2); +#endif + return(sym2); + } + sym1 = &sym2->s_next; + } + if (oldsym) sym2 = oldsym; + else + { + sym2 = (t_symbol *)t_getbytes(sizeof(*sym2)); + sym2->s_name = t_getbytes(length+1); + sym2->s_next = 0; + sym2->s_thing = 0; + strcpy(sym2->s_name, s); + } + *sym1 = sym2; +#ifdef DICT_DEBUG + post("appended at address %x", (int)sym2); +#endif + return (sym2); +} + +/* adapted gensym() from m_class.c */ +t_symbol *dict_key(t_dict *x, char *s) +{ + return (dict_dokey(x, s, 0)); +} + +/* adapted pd_bind() from m_pd.c */ +void dict_bind(t_dict *x, t_pd *obj, t_symbol *s) +{ +#ifdef DICT_DEBUG + post("bind %x to \"%s\" at %x", (int)obj, s->s_name, (int)s); +#endif + if (s->s_thing) + { +#ifdef DICT_DEBUG + post("(next one)"); +#endif + if (*s->s_thing == x->d_bindlist_class) + { + t_dict_bindlist *b = (t_dict_bindlist *)s->s_thing; + t_dict_bindelem *e = + (t_dict_bindelem *)getbytes(sizeof(t_dict_bindelem)); + e->e_next = b->b_list; + e->e_who = obj; + b->b_list = e; + } + else + { + t_dict_bindlist *b = + (t_dict_bindlist *)pd_new(x->d_bindlist_class); + t_dict_bindelem *e1 = + (t_dict_bindelem *)getbytes(sizeof(t_dict_bindelem)); + t_dict_bindelem *e2 = + (t_dict_bindelem *)getbytes(sizeof(t_dict_bindelem)); + b->b_list = e1; + e1->e_who = obj; + e1->e_next = e2; + e2->e_who = s->s_thing; + e2->e_next = 0; + s->s_thing = &b->b_pd; + } + } + else s->s_thing = obj; +} + +/* adapted pd_unbind() from m_pd.c */ +void dict_unbind(t_dict *x, t_pd *obj, t_symbol *s) +{ +#ifdef DICT_DEBUG + post("unbind %x from \"%s\" at %x", (int)obj, s->s_name, (int)s); +#endif + if (s->s_thing == obj) s->s_thing = 0; + else if (s->s_thing && *s->s_thing == x->d_bindlist_class) + { + /* bindlists always have at least two elements... if the number + goes down to one, get rid of the bindlist and bind the symbol + straight to the remaining element. */ + + t_dict_bindlist *b = (t_dict_bindlist *)s->s_thing; + t_dict_bindelem *e, *e2; + if ((e = b->b_list)->e_who == obj) + { + b->b_list = e->e_next; + freebytes(e, sizeof(t_dict_bindelem)); + } + else for (e = b->b_list; e2 = e->e_next; e = e2) + if (e2->e_who == obj) + { + e->e_next = e2->e_next; + freebytes(e2, sizeof(t_dict_bindelem)); + break; + } + if (!b->b_list->e_next) + { + s->s_thing = b->b_list->e_who; + freebytes(b->b_list, sizeof(t_dict_bindelem)); + pd_free(&b->b_pd); + } + } + else pd_error(obj, "%s: couldn't unbind", s->s_name); +} + +/* adapted pd_findbyclass() from m_pd.c */ +t_pd *dict_value(t_dict *x, t_symbol *s) +{ + if (!s->s_thing) return (0); + if (*s->s_thing == x->d_bindlist_class) + { + t_pd *x = 0; + t_dict_bindelem *e; + int warned = 0; + for (e = ((t_dict_bindlist *)s->s_thing)->b_list; e; e = e->e_next) + { + if (x && !warned) + { + post("warning: %s: multiply defined", s->s_name); + warned = 1; + } + x = e->e_who; + } + return (x); + } + return (s->s_thing); +} + +t_pd *dict_xvalue(t_dict *x, t_symbol *s) +{ + return (s && s != &s_ ? dict_value(x, dict_key(x, s->s_name)) : 0); +} + +int dict_forall(t_dict *x, t_symbol *s, t_dict_hook hook, void *hookarg) +{ + if (!s->s_thing) + return (0); + if (*s->s_thing == x->d_bindlist_class) + { + t_dict_bindelem *e = ((t_dict_bindlist *)s->s_thing)->b_list; + if (!e) + return (0); + if (!hook) + return (1); + do + if (!hook(e->e_who, hookarg)) + return (0); + while (e = e->e_next); + return (1); + } + return (hook ? hook(s->s_thing, hookarg) : 1); +} diff --git a/shared/common/dict.h b/shared/common/dict.h new file mode 100644 index 0000000..807bf9b --- /dev/null +++ b/shared/common/dict.h @@ -0,0 +1,27 @@ +/* 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. */ + +#ifndef __DICT_H__ +#define __DICT_H__ + +typedef struct _dict +{ + size_t d_hashsize; + t_symbol **d_hashtable; + t_class *d_bindlist_class; +} t_dict; + +typedef int (*t_dict_hook)(t_pd *x, void *arg); + +t_dict *dict_new(size_t hashsize); +void dict_free(t_dict *x); +t_symbol *dict_dokey(t_dict *x, char *s, t_symbol *oldsym); +t_symbol *dict_key(t_dict *x, char *s); +void dict_bind(t_dict *x, t_pd *obj, t_symbol *s); +void dict_unbind(t_dict *x, t_pd *obj, t_symbol *s); +t_pd *dict_value(t_dict *x, t_symbol *s); +t_pd *dict_xvalue(t_dict *x, t_symbol *s); +int dict_forall(t_dict *x, t_symbol *s, t_dict_hook hook, void *hookarg); + +#endif |