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 *findleft() - null iff not found * const *findright() * void destroy() - destroys container, doesn't delete elements * * initial implementation: flat array of (left,right) pairs */ struct __pair { l; r; }; "; my $bodytemplate = join "", ; 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_t; typedef __right_t; typedef struct { __pairarray a; long nextidx; } ; static inline int _init ( *m) { m->nextidx = 0; return __pairarray_init (&m->a); } static inline long _size ( *m) { return __pairarray_size (&m->a); } static inline void _foreach ( *m, int (*fn)(, , void *), void *p) { long i, sz; sz = m->nextidx; for (i = 0; i < sz; i++) { struct __pair *pair; pair = __pairarray_getaddr (&m->a, i); if ((*fn)(pair->l, pair->r, p) != 0) break; } } static inline int _add ( *m, l, r) { long i, sz; struct __pair newpair; int err; sz = m->nextidx; /* Make sure we're not duplicating. */ for (i = 0; i < sz; i++) { struct __pair *pair; pair = __pairarray_getaddr (&m->a, i); assert ((*)(l, pair->l) != 0); if ((*)(l, pair->l) == 0) abort(); assert ((*)(r, pair->r) != 0); if ((*)(r, pair->r) == 0) abort(); } newpair.l = l; newpair.r = r; if (sz >= LONG_MAX - 1) return ENOMEM; err = __pairarray_grow (&m->a, sz+1); if (err) return err; __pairarray_set (&m->a, sz, newpair); m->nextidx++; return 0; } static inline const __right_t * _findleft ( *m, l) { long i, sz; sz = _size (m); for (i = 0; i < sz; i++) { struct __pair *pair; pair = __pairarray_getaddr (&m->a, i); if ((*)(l, pair->l) == 0) return &pair->r; } return 0; } static inline const __left_t * _findright ( *m, r) { long i, sz; sz = _size (m); for (i = 0; i < sz; i++) { struct __pair *pair; pair = __pairarray_getaddr (&m->a, i); if ((*)(r, pair->r) == 0) return &pair->l; } return 0; } struct __printstat { FILE *f; int comma; }; static inline int __printone ( l, r, void *p) { struct __printstat *ps = p; fprintf(ps->f, ps->comma ? ", (" : "("); ps->comma = 1; (*)(l, ps->f); fprintf(ps->f, ","); (*)(r, ps->f); fprintf(ps->f, ")"); return 0; } static inline void _printmap ( *m, FILE *f) { struct __printstat ps; ps.comma = 0; ps.f = f; fprintf(f, "("); _foreach (m, __printone, &ps); fprintf(f, ")"); } static inline void _destroy ( *m) { __pairarray_destroy (&m->a); }