--- /dev/null
+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__
+\f
+/* 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);
+}