chiark / gitweb /
045ea54d7f92f6563c13e64b56bfa343564020e3
[mLib] / struct / sym.3
1 .\" -*-nroff-*-
2 .de VS
3 .sp 1
4 .RS
5 .nf
6 .ft B
7 ..
8 .de VE
9 .ft R
10 .fi
11 .RE
12 .sp 1
13 ..
14 .TH sym 3 "8 May 1999" "Straylight/Edgeware" "mLib utilities library"
15 .SH NAME
16 sym \- symbol table manager
17 .\" @sym_create
18 .\" @sym_destroy
19 .\" @sym_find
20 .\" @sym_remove
21 .\" @sym_mkiter
22 .\" @sym_next
23 .\"
24 .\" @SYM_NAME
25 .\" @SYM_LEN
26 .\" @SYM_HASH
27 .\"
28 .SH SYNOPSIS
29 .nf
30 .B "#include <mLib/sym.h>"
31
32 .B "type struct { ...\& } sym_table;"
33 .B "type struct { ...\& } sym_base;"
34 .B "type struct { ...\& } sym_iter;"
35
36 .BI "void sym_create(sym_table *" t );
37 .BI "void sym_destroy(sym_table *" t );
38
39 .ds mT \fBvoid *sym_find(
40 .BI "\*(mTsym_table *" t ,
41 .BI "\h'\w'\*(mT'u'const char *" n ", long " l ,
42 .BI "\h'\w'\*(mT'u'size_t " sz ", unsigned *" f );
43 .BI "void sym_remove(sym_table *" t ", void *" b );
44
45 .BI "const char *SYM_NAME(const void *" p );
46 .BI "size_t SYM_LEN(const void *" p );
47 .BI "uint32 SYM_HASH(const void *" p );
48
49 .BI "void sym_mkiter(sym_iter *" i ", sym_table *" t );
50 .BI "void *sym_next(sym_iter *" i );
51 .fi
52 .SH "DESCRIPTION"
53 The
54 .B sym
55 functions implement a data structure often described as a dictionary, a
56 finite map, an associative array, or a symbol table.  It associates
57 .I values
58 with
59 .I keys
60 such that the value corresponding to a given key can be found quickly.
61 Additionally, all stored associations can be enumerated.
62 .PP
63 The interface provides an
64 .I intrusive
65 symbol table.  The data objects stored in the table must include a small
66 header used by the symbol table manager.  This reduces the amount of
67 pointer fiddling that needs to be done, and in practice doesn't seem to
68 be much of a problem.  It's also fairly easy to construct a
69 non-intrusive interface if you really want one.
70 .PP
71 There are three main data structures involved in the interface:
72 .TP
73 .B sym_table
74 Keeps track of the information associated with a particular table.
75 .TP
76 .B sym_base
77 The header which must be attached to the front of all the value
78 objects.
79 .TP
80 .B sym_iter
81 An iterator object, used for enumerating all of the associations stored
82 in a symbol table.
83 .PP
84 All of the above data structures should be considered
85 .IR opaque :
86 don't try looking inside.  Representations have changed in the past, and
87 they may change again in the future.
88 .SS "Creation and destruction"
89 The
90 .B sym_table
91 object itself needs to be allocated by the caller.  It is initialized by
92 passing it to the function
93 .BR sym_create .
94 After initialization, the table contains no entries.
95 .PP
96 Initializing a symbol table involves allocating some memory.  If this
97 allocation fails, an
98 .B EXC_NOMEM
99 exception is raised.
100 .PP
101 When a symbol table is no longer needed, the memory occupied by the
102 values and other maintenance structures can be reclaimed by calling
103 .BR sym_destroy .
104 Any bits of user data attached to values should previously have been
105 destroyed.
106 .SS "Adding, searching and removing"
107 Most of the actual work is done by the function
108 .BR sym_find .
109 It does both lookup and creation, depending on its arguments.  To do its
110 job, it needs to know the following bits of information:
111 .TP
112 .BI "sym_table *" t
113 A pointer to a symbol table to manipulate.
114 .TP
115 .BI "const char *" n
116 The address of the
117 .I key
118 to look up or create.  Usually this will be a simple text string,
119 although it can actually be any arbitrary binary data.
120 .TP
121 .BI "long " l
122 The length of the key.  If this is \-1,
123 .B sym_find
124 assumes that the key is a null-terminated string, and calculates its
125 length itself.  This is entirely equivalent to passing
126 .BI strlen( n )\fR.
127 .TP
128 .BI "size_t " sz
129 The size of the value block to allocate if the key could not be found.
130 If this is zero, no value is allocated, and a null pointer is returned
131 to indicate an unsuccessful lookup.
132 .TP
133 .BI "unsigned *" f
134 The address of a `found' flag to set.  This is an output parameter.  On
135 exit,
136 .B sym_find
137 will set the value of
138 .BI * f
139 to zero if the key could not be found, or nonzero if it was found.  This
140 can be used to tell whether the value returned has been newly allocated,
141 or whether it was already in the table.
142 .PP
143 A terminating null byte is appended to the copy of the symbol's name in
144 memory.  This is not considered to be a part of the symbol's name, and
145 does not contribute to the name's length as reported by the
146 .B SYM_LEN
147 macro.
148 .PP
149 A symbol can be removed from the table by calling
150 .BR sym_remove ,
151 passing the symbol table itself, and the value block that needs
152 removing.
153 .SS "Enquiries about symbols"
154 Three macros are provided to enable simple enquiries about a symbol.
155 Given a pointer
156 .I s
157 to a symbol table entry,
158 .BI SYM_LEN( s )
159 returns the length of the symbol's name (excluding any terminating null
160 byte);
161 .BI SYM_NAME( s )
162 returns a pointer to the symbol's name; and
163 .BI SYM_HASH( s )
164 returns the symbol's hash value.
165 .SS "Enumerating symbols"
166 Enumerating the values in a symbol table is fairly simple.  Allocate a
167 .B sym_iter
168 object from somewhere.  Attach it to a symbol table by calling
169 .BR sym_mkiter ,
170 and passing in the addresses of the iterator and the symbol table.
171 Then, each call to
172 .B sym_next
173 will return a different value from the symbol table, until all of them
174 have been enumerated, at which point,
175 .B sym_next
176 returns a null pointer.
177 .PP
178 It's safe to remove the symbol you've just been returned by
179 .BR sym_next .
180 However, it's not safe to remove any other symbol.  So don't do that.
181 .PP
182 When you've finished with an iterator, it's safe to just throw it away.
183 You don't need to call any functions beforehand.
184 .SS "Use in practice"
185 In normal use, the keys are simple strings (usually identifiers from
186 some language), and the values are nontrivial structures providing
187 information about types and values.
188 .PP
189 In this case, you'd define something like the following structure for
190 your values:
191 .VS
192 typedef struct val {
193   sym_base _base;       /* Symbol header */
194   unsigned type;        /* Type of this symbol */
195   int dispoff;          /* Which display variable is in */
196   size_t frameoff;      /* Offset of variable in frame */
197 } val;
198 .VE
199 Given a pointer
200 .I v
201 to a
202 .BR val ,
203 you can find the variable's name by calling
204 .BI SYM_NAME( v )\fR.
205 .PP
206 You can look up a name in the table by saying something like:
207 .VS
208 val *v = sym_find(t, name, -1, 0, 0);
209 if (!v)
210   error("unknown variable `%s'", name);
211 .VE
212 You can add in a new variable by saying something like
213 .VS
214 unsigned f;
215 val *v = sym_find(t, name, -1, sizeof(val), &f);
216 if (f)
217   error("variable `%s' already exists", name);
218 /* fill in v */
219 .VE
220 You can examine all the variables in your symbol table by saying
221 something like:
222 .VS
223 sym_iter i;
224 val *v;
225
226 for (sym_mkiter(&i, t); (v = sym_next(&i)) != 0; ) {
227   /* ... */
228 }
229 .VE
230 That ought to be enough examples to be getting on with.
231 .SS Implementation
232 The symbol table is an extensible hashtable, using the universal hash
233 function described in
234 .BR unihash (3)
235 and the global hashing key.  The hash chains are kept very short
236 (probably too short, actually).  Every time a symbol is found, its block
237 is promoted to the front of its bin chain so it gets found faster next
238 time.
239 .SH SEE ALSO
240 .BR hash (3),
241 .BR mLib (3).
242 .SH AUTHOR
243 Mark Wooding, <mdw@distorted.org.uk>