package t_bimap; use strict; use vars qw(@ISA); require t_template; require t_array; @ISA=qw(t_template); my @parms = qw(NAME LEFT RIGHT LEFTCMP RIGHTCMP LEFTPRINT RIGHTPRINT); my %defaults = (); my $headertemplate = "/* * bidirectional mapping table, add-only * * Parameters: * NAME * LEFT, RIGHT - types * LEFTCMP, RIGHTCMP - comparison functions * * Methods: * int init() - nonzero is error code, if any possible * long size() * void foreach(int (*)(LEFT, RIGHT, void*), void*) * int add(LEFT, RIGHT) - 0 = success, -1 = allocation failure * const <RIGHT> *findleft(<LEFT>) - null iff not found * const <LEFT> *findright(<RIGHT>) * void destroy() - destroys container, doesn't delete elements * * initial implementation: flat array of (left,right) pairs */ struct <NAME>__pair { <LEFT> l; <RIGHT> r; }; "; my $bodytemplate = join "", <DATA>; sub new { # no args my $self = {}; bless $self; $self->init(\@parms, \%defaults, []); return $self; } sub output { my ($self, $fh) = @_; my $a = new t_array; $a->setparm("NAME", $self->{values}{"NAME"} . "__pairarray"); $a->setparm("TYPE", "struct " . $self->{values}{"NAME"} . "__pair"); print $fh "/* start of ", ref($self), " header template */\n"; print $fh $self->substitute($headertemplate); print $fh "/* end of ", ref($self), " header template */\n"; $a->output($fh); print $fh "/* start of ", ref($self), " body template */\n"; print $fh $self->substitute($bodytemplate); print $fh "/* end of ", ref($self), " body template */\n"; } 1; __DATA__ /* for use in cases where text substitutions may not work, like putting "const" before a type that turns out to be "char *" */ typedef <LEFT> <NAME>__left_t; typedef <RIGHT> <NAME>__right_t; typedef struct { <NAME>__pairarray a; long nextidx; } <NAME>; static inline int <NAME>_init (<NAME> *m) { m->nextidx = 0; return <NAME>__pairarray_init (&m->a); } static inline long <NAME>_size (<NAME> *m) { return <NAME>__pairarray_size (&m->a); } static inline void <NAME>_foreach (<NAME> *m, int (*fn)(<LEFT>, <RIGHT>, void *), void *p) { long i, sz; sz = m->nextidx; for (i = 0; i < sz; i++) { struct <NAME>__pair *pair; pair = <NAME>__pairarray_getaddr (&m->a, i); if ((*fn)(pair->l, pair->r, p) != 0) break; } } static inline int <NAME>_add (<NAME> *m, <LEFT> l, <RIGHT> r) { long i, sz; struct <NAME>__pair newpair; int err; sz = m->nextidx; /* Make sure we're not duplicating. */ for (i = 0; i < sz; i++) { struct <NAME>__pair *pair; pair = <NAME>__pairarray_getaddr (&m->a, i); assert ((*<LEFTCMP>)(l, pair->l) != 0); if ((*<LEFTCMP>)(l, pair->l) == 0) abort(); assert ((*<RIGHTCMP>)(r, pair->r) != 0); if ((*<RIGHTCMP>)(r, pair->r) == 0) abort(); } newpair.l = l; newpair.r = r; if (sz >= LONG_MAX - 1) return ENOMEM; err = <NAME>__pairarray_grow (&m->a, sz+1); if (err) return err; <NAME>__pairarray_set (&m->a, sz, newpair); m->nextidx++; return 0; } static inline const <NAME>__right_t * <NAME>_findleft (<NAME> *m, <LEFT> l) { long i, sz; sz = <NAME>_size (m); for (i = 0; i < sz; i++) { struct <NAME>__pair *pair; pair = <NAME>__pairarray_getaddr (&m->a, i); if ((*<LEFTCMP>)(l, pair->l) == 0) return &pair->r; } return 0; } static inline const <NAME>__left_t * <NAME>_findright (<NAME> *m, <RIGHT> r) { long i, sz; sz = <NAME>_size (m); for (i = 0; i < sz; i++) { struct <NAME>__pair *pair; pair = <NAME>__pairarray_getaddr (&m->a, i); if ((*<RIGHTCMP>)(r, pair->r) == 0) return &pair->l; } return 0; } struct <NAME>__printstat { FILE *f; int comma; }; static inline int <NAME>__printone (<LEFT> l, <RIGHT> r, void *p) { struct <NAME>__printstat *ps = p; fprintf(ps->f, ps->comma ? ", (" : "("); ps->comma = 1; (*<LEFTPRINT>)(l, ps->f); fprintf(ps->f, ","); (*<RIGHTPRINT>)(r, ps->f); fprintf(ps->f, ")"); return 0; } static inline void <NAME>_printmap (<NAME> *m, FILE *f) { struct <NAME>__printstat ps; ps.comma = 0; ps.f = f; fprintf(f, "("); <NAME>_foreach (m, <NAME>__printone, &ps); fprintf(f, ")"); } static inline void <NAME>_destroy (<NAME> *m) { <NAME>__pairarray_destroy (&m->a); }