chiark / gitweb /
New manpages.
[mLib] / assoc.c
1 /* -*-c-*-
2  *
3  * $Id: assoc.c,v 1.2 2001/01/21 19:04:59 mdw Exp $
4  *
5  * Assocation tables
6  *
7  * (c) 2000 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the mLib utilities library.
13  *
14  * mLib is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * mLib is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with mLib; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Revision history --------------------------------------------------* 
31  *
32  * $Log: assoc.c,v $
33  * Revision 1.2  2001/01/21 19:04:59  mdw
34  * Fix bugs.
35  *
36  * Revision 1.1  2001/01/20 11:50:58  mdw
37  * Hash tables indexed by atoms, to avoid expense of hashing keys on each
38  * lookup, and to reduce storage used by key texts.
39  *
40  */
41
42 /*----- Header files ------------------------------------------------------*/
43
44 #include "alloc.h"
45 #include "assoc.h"
46 #include "atom.h"
47 #include "hash.h"
48
49 /*----- Main code ---------------------------------------------------------*/
50
51 /* --- @assoc_create@ --- *
52  *
53  * Arguments:   @assoc_table *t@ = pointer to an association table
54  *
55  * Returns:     ---
56  *
57  * Use:         Creates a new association table.
58  */
59
60 void assoc_create(assoc_table *t)
61 {
62   hash_create(&t->t, SYM_INITSZ);
63   t->load = SYM_LIMIT(SYM_INITSZ);
64 }
65
66 /* --- @assoc_destroy@ --- *
67  *
68  * Arguments:   @assoc_table *t@ = pointer to an association table
69  *
70  * Returns:     ---
71  *
72  * Use:         Destroys an association table.
73  */
74
75 void assoc_destroy(assoc_table *t)
76 {
77   hash_iter i;
78
79   HASH_MKITER(&i, &t->t);
80   for (;;) {
81     hash_base *p;
82     HASH_NEXT(&i, p);
83     if (!p)
84       break;
85     x_free(t->t.a, p);
86   }
87   hash_destroy(&t->t);
88 }
89
90 /* --- @assoc_find@ --- *
91  *
92  * Arguments:   @assoc_table *t@ = pointer to an association table
93  *              @atom *a@ = an atom to label the item
94  *              @size_t sz@ = size of block to allocate
95  *              @unsigned *f@ = pointer to `found' flag
96  *
97  * Returns:     A pointer to the item located or null.
98  *
99  * Use:         Looks up an atom in an association table.  If the atom is
100  *              found, the association is returned.  If not, and @sz@ is
101  *              zero, a null pointer is returned.  Otherwise, a block of size
102  *              @sz@ is allocated, its @assoc_base@ header is filled in, and
103  *              the pointer returned.  The flag @*f@ is cleared if the item
104  *              couldn't be found, or set if it was.
105  *
106  *              All the atoms used in a particular table should 
107  */
108
109 void *assoc_find(assoc_table *t, atom *a, size_t sz, unsigned *f)
110 {
111   hash_base **bin = HASH_BIN(&t->t, a->b.b.hash), **p;
112   assoc_base *q;
113
114   /* --- Try to find the association --- */
115
116   for (p = bin; *p; p = &(*p)->next) {
117     q = (assoc_base *)*p;
118     if (q->a == a) {
119       *p = q->b.next;
120       q->b.next = *bin;
121       *bin = &q->b;
122       if (f) *f = 1;
123       return (q);
124     }
125   }
126
127   /* --- Failed to find a match --- */
128
129   if (f) *f = 0;
130   if (!sz) return (0);
131
132   /* --- Make a new assoication --- */
133
134   q = x_alloc(t->t.a, sz);
135   q->a = a;
136   q->b.next = *bin;
137   q->b.hash = ATOM_HASH(a);
138   *bin = &q->b;
139
140   /* --- Maybe extend the table --- */
141
142   if (t->load)
143     t->load--;
144   if (!t->load && hash_extend(&t->t))
145     t->load = SYM_LIMIT(t->t.mask + 1);
146   return (q);
147 }
148
149 /* --- @assoc_remove@ --- *
150  *
151  * Arguments:   @assoc_table *t@ = pointer to an association table
152  *              @void *p@ = pointer to a block to remove
153  *
154  * Returns:     ---
155  *
156  * Use:         Removes an association from a table.
157  */
158
159 void assoc_remove(assoc_table *t, void *p)
160 {
161   assoc_base *q = p;
162   hash_remove(&t->t, &q->b);
163   x_free(t->t.a, q);
164   t->load++;
165 }
166
167 /* --- @assoc_mkiter@, @assoc_next@ --- *
168  *
169  * Arguments:   @assoc_iter *i@ = pointer to an iterator
170  *              @assoc_table *t@ = pointer to an association table
171  *
172  * Returns:     Next association, or null, for @assoc_next@; nothing for
173  *              @assoc_mkiter@.
174  *
175  * Use:         Iterates over the associations in a table.
176  */
177
178 void assoc_mkiter(assoc_iter *i, assoc_table *t) { ASSOC_MKITER(i, t); }
179 void *assoc_next(assoc_iter *i) { void *p; ASSOC_NEXT(i, p); return (p); }
180
181 /*----- That's all, folks -------------------------------------------------*/