chiark / gitweb /
768d229a6bcd9a388a64583c05f603071147367d
[mLib] / atom.c
1 /* -*-c-*-
2  *
3  * $Id: atom.c,v 1.4 2003/12/15 20:53:47 mdw Exp $
4  *
5  * Atom management
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: atom.c,v $
33  * Revision 1.4  2003/12/15 20:53:47  mdw
34  * Add global unihash table; use universal hashing instead of CRC.
35  *
36  * Revision 1.3  2001/01/25 21:13:15  mdw
37  * New function allowing an atom's length to be specified at intern time.
38  *
39  * Revision 1.2  2001/01/21 19:04:51  mdw
40  * Include `crc32.h' for @CRC32@ macro.
41  *
42  * Revision 1.1  2001/01/20 11:50:16  mdw
43  * Implementation of atom tables (for example, as found in X11).
44  *
45  */
46
47 /*----- Header files ------------------------------------------------------*/
48
49 #include <stdio.h>
50 #include <string.h>
51
52 #include "alloc.h"
53 #include "atom.h"
54 #include "hash.h"
55 #include "sym.h"
56 #include "unihash.h"
57
58 /*----- Static variables --------------------------------------------------*/
59
60 static atom_table atoms;
61
62 /*----- Handy macros ------------------------------------------------------*/
63
64 #define ATOM_RESOLVE(t) do {                                            \
65   if (t == ATOM_GLOBAL)                                                 \
66     t = &atoms;                                                         \
67   if (!t->t.t.v)                                                        \
68     atom_createtable(t);                                                \
69 } while (0)
70
71 /*----- Main code ---------------------------------------------------------*/
72
73 /* --- @atom_createtable@ --- *
74  *
75  * Arguments:   @atom_table *t@ = pointer to an atom table
76  *
77  * Returns:     ---
78  *
79  * Use:         Initializes an atom table.
80  */
81
82 void atom_createtable(atom_table *t)
83 {
84   sym_create(&t->t);
85   t->g = 0;
86   t->gseq = 0;
87 }
88
89 /* --- @atom_destroytable@ --- *
90  *
91  * Arguments:   @atom_table *t@ = pointer to an atom table
92  *
93  * Returns:     ---
94  *
95  * Use:         Destroys all of the atoms in an atom table.  All of the atoms
96  *              (including uninterned atoms) are freed.  Any references to
97  *              atoms from the table become invalid, and any association
98  *              tables dependent on the atom table are unusable, except that
99  *              they may be destroyed safely.
100  */
101
102 void atom_destroytable(atom_table *t)
103 {
104   atom *a, *aa;
105
106   ATOM_RESOLVE(t);
107   for (a = (atom *)t->g; a; a = aa) {
108     aa = (atom *)a->b.b.next;
109     x_free(t->t.t.a, a);
110   }
111   sym_destroy(&t->t);
112 }
113
114 /* --- @atom_intern@, @atom_nintern@ --- *
115  *
116  * Arguments:   @atom_table *t@ = pointer to an atom table
117  *              @const char *p@ = pointer to the string to intern
118  *              @size_t n@ = size of the string (for @atom_nintern)
119  *
120  * Returns:     A pointer to the atom block for the given symbol string.
121  *
122  * Use:         Interns an atom, returning the atom block.  The string can be
123  *              extracted from the atom by means of the @ATOM_NAME@ macro.
124  */
125
126 atom *atom_intern(atom_table *t, const char *p)
127 {
128   atom *a;
129   unsigned f;
130
131   ATOM_RESOLVE(t);
132   a = sym_find(&t->t, p, -1, sizeof(atom), &f);
133   if (!f)
134     a->f = 0;
135   return (a);
136 }
137
138 atom *atom_nintern(atom_table *t, const char *p, size_t n)
139 {
140   atom *a;
141   unsigned f;
142
143   ATOM_RESOLVE(t);
144   a = sym_find(&t->t, p, n, sizeof(atom), &f);
145   if (!f)
146     a->f = 0;
147   return (a);
148 }
149
150 /* --- @atom_gensym@ --- *
151  *
152  * Arguments:   @atom_table *t@ = pointer to a symbol table
153  *
154  * Returns:     A pointer to a new atom block, not previously interned.
155  *
156  * Use:         Creates a new, uninterned atom.  This atom will never be
157  *              returned by either @atom_intern@ or any other call to
158  *              @atom_gensym@, while the symbol table exists.
159  */
160
161 atom *atom_gensym(atom_table *t)
162 {
163   atom *a;
164   char buf[64];
165   size_t sz;
166
167   ATOM_RESOLVE(t);
168   sprintf(buf, "*gen-%lu*", t->gseq++);
169   sz = strlen(buf) + 1;
170   a = x_alloc(t->t.t.a, sizeof(atom) + sz);
171   a->b.name = (char *)(a + 1);
172   memcpy(a->b.name, buf, sz);
173   a->b.len = sz;
174   a->b.b.hash = UNIHASH(&unihash_global, buf, sz);
175   a->f = ATOMF_GENSYM;
176   a->b.b.next = t->g;
177   t->g = &a->b.b;
178   return (a);
179 }
180
181 /* --- @atom_name@ --- *
182  *
183  * Arguments:   @atom *a@ = pointer to an atom
184  *
185  * Returns:     The atom's textual name.
186  *
187  * Use:         Given an atom, returns the name with which it was interned
188  *              (or a made-up name if it was created using @gensym@.
189  */
190
191 const char *atom_name(const atom *a) { return ATOM_NAME(a); }
192
193 /* --- @atom_len@ --- *
194  *
195  * Arguments:   @atom *a@ = pointer to an atom
196  *
197  * Returns:     The atom string's length.
198  *
199  * Use:         Given an atom, return the length of its textual
200  *              representation.
201  */
202
203 size_t atom_len(const atom *a) { return ATOM_LEN(a); }
204
205 /* --- @atom_hash@ --- *
206  *
207  * Arguments:   @atom *a@ = pointer to an atom
208  *
209  * Returns:     The atom's hash.
210  *
211  * Use:         Given an atom, returns its hash.
212  */
213
214 uint32 atom_hash(const atom *a) { return ATOM_HASH(a); }
215
216 /* --- @atom_mkiter@ , @atom_next@ --- *
217  *
218  * Arguments:   @atom_table *t@ = pointer to an atom table
219  *              @atom_iter *i@ = pointer to an iterator structure
220  *
221  * Returns:     Next atom, for @atom_next@; nothing for @atom_mkiter@.
222  *
223  * Use:         Iterates over atoms (both interned and uninterned).
224  */
225
226 void atom_mkiter(atom_iter *i, atom_table *t)
227 {
228   ATOM_RESOLVE(t);
229   i->i.i.t = &t->t.t;
230   i->i.i.p = t->g;
231   i->i.i.i = 0;
232 }
233
234 atom *atom_next(atom_iter *i)
235 {
236   atom *a;
237   SYM_NEXT(&i->i, a);
238   return (a);
239 }
240
241 /*----- That's all, folks -------------------------------------------------*/