2 * Copyright (c) 2001 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 #ident "$Id: symbols.cc,v 1.12 2004/10/04 01:10:59 steve Exp $"
32 * The keys of the symbol table are null terminated strings. Keep them
33 * in a string buffer, with the strings separated by a single null,
34 * for compact use of memory. This also makes it easy to delete the
35 * entire lot of keys, simply by deleting the heaps.
37 * The key_strdup() function below allocates the strings from this
38 * buffer, possibly making a new buffer if needed.
41 struct key_strings
*next
;
42 char data
[64*1024 - sizeof(struct key_strings
*)];
45 struct symbol_table_s
{
46 struct tree_node_
*root
;
47 struct key_strings
*str_chunk
;
51 static char*key_strdup(struct symbol_table_s
*tab
, const char*str
)
53 unsigned len
= strlen(str
);
54 assert( (len
+1) <= sizeof tab
->str_chunk
->data
);
56 if ( (len
+1) > (sizeof tab
->str_chunk
->data
- tab
->str_used
) ) {
57 key_strings
*tmp
= new key_strings
;
58 tmp
->next
= tab
->str_chunk
;
63 char*res
= tab
->str_chunk
->data
+ tab
->str_used
;
64 tab
->str_used
+= len
+ 1;
70 * This is a B-Tree data structure, where there are nodes and
73 * Nodes have a bunch of pointers to children. Each child pointer has
74 * associated with it a key that is the largest key referenced by that
75 * child. So, if the key being searched for has a value <= the first
76 * key of a node, then the value is in the first child.
78 * leaves have a sorted table of key-value pairs. The search can use a
79 * simple binary search to find an item. Each key represents an item.
82 const unsigned leaf_width
= 254;
83 const unsigned node_width
= 508;
88 struct tree_node_
*parent
;
96 struct tree_node_
*child
[node_width
];
101 static inline char* node_last_key(struct tree_node_
*node
)
103 while (node
->leaf_flag
== false)
104 node
= node
->child
[node
->count
-1];
106 return node
->leaf
[node
->count
-1].key
;
110 * Allocate a new symbol table means creating the table structure and
111 * a root node, and initializing the pointers and members of the root
114 symbol_table_t
new_symbol_table(void)
116 symbol_table_t tbl
= new struct symbol_table_s
;
117 tbl
->root
= new struct tree_node_
;
118 tbl
->root
->leaf_flag
= false;
119 tbl
->root
->count
= 0;
120 tbl
->root
->parent
= 0;
122 tbl
->str_chunk
= new key_strings
;
123 tbl
->str_chunk
->next
= 0;
129 static void delete_symbol_node(struct tree_node_
*cur
)
131 if (! cur
->leaf_flag
) {
132 for (unsigned idx
= 0 ; idx
< cur
->count
; idx
+= 1)
133 delete_symbol_node(cur
->child
[idx
]);
139 void delete_symbol_table(symbol_table_t tab
)
141 delete_symbol_node(tab
->root
);
142 while (tab
->str_chunk
) {
143 key_strings
*tmp
= tab
->str_chunk
;
144 tab
->str_chunk
= tmp
->next
;
151 /* Do as split_leaf_ does, but for nodes. */
152 static void split_node_(struct tree_node_
*cur
)
154 unsigned int idx
, idx1
, idx2
, tmp
;
155 struct tree_node_
*new_node
;
157 assert(!cur
->leaf_flag
);
158 if (cur
->parent
) assert(! cur
->parent
->leaf_flag
);
160 while (cur
->count
== node_width
)
162 /* Create a new node to hold half the data from cur. */
163 new_node
= new struct tree_node_
;
164 new_node
->leaf_flag
= false;
165 new_node
->count
= cur
->count
/ 2;
167 /* cur is not root; new_node becomes sibling. */
168 new_node
->parent
= cur
->parent
;
170 /* Move the last half of the data from the end of the old node
171 to the beginning of the new node. At the same time, reduce
172 the size of the old node. */
173 idx1
= new_node
->count
;
178 new_node
->child
[idx1
] = cur
->child
[idx2
];
179 new_node
->child
[idx1
]->parent
= new_node
;
183 assert(new_node
->count
> 0);
184 assert(cur
->count
> 0);
186 if (cur
->parent
== 0) {
187 /* cur is root. Move first half of children to
188 another new node, and put the two new nodes
189 in cur. The plan here is to make cur into
190 the new root and split its contents into 2
193 new_node
->parent
= cur
;
194 struct tree_node_
*new2_node
= new struct tree_node_
;
195 new2_node
->leaf_flag
= false;
196 new2_node
->count
= cur
->count
;
197 new2_node
->parent
= cur
;
198 for (idx
= 0; idx
< cur
->count
; idx
+= 1) {
199 new2_node
->child
[idx
] = cur
->child
[idx
];
200 new2_node
->child
[idx
]->parent
= new2_node
;
202 cur
->child
[0] = new2_node
;
203 cur
->child
[1] = new_node
;
205 /* no more ancestors, stop the while loop */
209 /* cur is not root. hook new_node to cur->parent. */
211 while (cur
->parent
->child
[idx
] != cur
) {
212 assert(idx
< cur
->parent
->count
);
218 for (tmp
= cur
->parent
->count
; tmp
> idx
; tmp
-= 1)
219 cur
->parent
->child
[tmp
] = cur
->parent
->child
[tmp
-1];
221 cur
->parent
->child
[idx
] = new_node
;
222 cur
->parent
->count
+= 1;
224 /* check the ancestor */
230 * This function takes a leaf node and splits in into two. Move half
231 * the leaf keys into the new node, and add the new leaf into the
234 static struct tree_node_
* split_leaf_(struct tree_node_
*cur
)
236 assert(cur
->leaf_flag
);
238 assert(! cur
->parent
->leaf_flag
);
240 /* Create a new leaf to hold half the data from the old leaf. */
241 struct tree_node_
*new_leaf
= new struct tree_node_
;
242 new_leaf
->leaf_flag
= true;
243 new_leaf
->count
= cur
->count
/ 2;
244 new_leaf
->parent
= cur
->parent
;
246 /* Move the last half of the data from the end of the old leaf
247 to the beginning of the new leaf. At the same time, reduce
248 the size of the old leaf. */
249 unsigned idx1
= new_leaf
->count
;
250 unsigned idx2
= cur
->count
;
254 new_leaf
->leaf
[idx1
] = cur
->leaf
[idx2
];
258 assert(new_leaf
->count
> 0);
259 assert(cur
->count
> 0);
262 while (cur
->parent
->child
[idx
] != cur
) {
263 assert(idx
< cur
->parent
->count
);
269 for (unsigned tmp
= cur
->parent
->count
; tmp
> idx
; tmp
-= 1)
270 cur
->parent
->child
[tmp
] = cur
->parent
->child
[tmp
-1];
272 cur
->parent
->child
[idx
] = new_leaf
;
273 cur
->parent
->count
+= 1;
275 if (cur
->parent
->count
== node_width
)
276 split_node_(cur
->parent
);
283 * This function searches tree recursively for the key. If the value
284 * is not found (and we are at a leaf) then set the key with the given
285 * value. If the key is found, set the value only if the force_flag is
289 static symbol_value_t
find_value_(symbol_table_t tbl
, struct tree_node_
*cur
,
290 const char*key
, symbol_value_t val
,
293 if (cur
->leaf_flag
) {
297 /* If we run out of keys in the leaf, then add
298 this at the end of the leaf. */
299 if (idx
== cur
->count
) {
300 cur
->leaf
[idx
].key
= key_strdup(tbl
, key
);
301 cur
->leaf
[idx
].val
= val
;
303 if (cur
->count
== leaf_width
)
309 int rc
= strcmp(key
, cur
->leaf
[idx
].key
);
311 /* If we found the key already in the table, then
312 set the new value and break. */
315 cur
->leaf
[idx
].val
= val
;
316 return cur
->leaf
[idx
].val
;
319 /* If this key goes before the current key, then
320 push all the following entries back and add
323 for (unsigned tmp
= cur
->count
; tmp
> idx
; tmp
-= 1)
324 cur
->leaf
[tmp
] = cur
->leaf
[tmp
-1];
326 cur
->leaf
[idx
].key
= key_strdup(tbl
, key
);
327 cur
->leaf
[idx
].val
= val
;
329 if (cur
->count
== leaf_width
)
339 /* Do a binary search within the inner node. */
341 unsigned max
= cur
->count
;
342 unsigned idx
= max
/2;
344 int rc
= strcmp(key
, node_last_key(cur
->child
[idx
]));
346 return find_value_(tbl
, cur
->child
[idx
],
347 key
, val
, force_flag
);
352 if (min
== cur
->count
)
353 return find_value_(tbl
, cur
->child
[idx
],
354 key
, val
, force_flag
);
356 return find_value_(tbl
, cur
->child
[max
],
357 key
, val
, force_flag
);
359 idx
= min
+ (max
-min
)/2;
364 return find_value_(tbl
, cur
->child
[idx
],
365 key
, val
, force_flag
);
366 idx
= min
+ (max
-min
)/2;
372 { symbol_value_t tmp
;
378 void sym_set_value(symbol_table_t tbl
, const char*key
, symbol_value_t val
)
380 if (tbl
->root
->count
== 0) {
381 /* Handle the special case that this is the very first
382 value in the symbol table. Create the first leaf node
383 and initialize the pointers. */
384 struct tree_node_
*cur
= new struct tree_node_
;
385 cur
->leaf_flag
= true;
386 cur
->parent
= tbl
->root
;
388 cur
->leaf
[0].key
= key_strdup(tbl
, key
);
389 cur
->leaf
[0].val
= val
;
391 tbl
->root
->count
= 1;
392 tbl
->root
->child
[0] = cur
;
394 find_value_(tbl
, tbl
->root
, key
, val
, true);
398 symbol_value_t
sym_get_value(symbol_table_t tbl
, const char*key
)
403 if (tbl
->root
->count
== 0) {
404 /* Handle the special case that this is the very first
405 value in the symbol table. Create the first leaf node
406 and initialize the pointers. */
407 struct tree_node_
*cur
= new struct tree_node_
;
408 cur
->leaf_flag
= true;
409 cur
->parent
= tbl
->root
;
411 cur
->leaf
[0].key
= key_strdup(tbl
, key
);
412 cur
->leaf
[0].val
= def
;
414 tbl
->root
->count
= 1;
415 tbl
->root
->child
[0] = cur
;
416 return cur
->leaf
[0].val
;
418 return find_value_(tbl
, tbl
->root
, key
, def
, false);
424 * $Log: symbols.cc,v $
425 * Revision 1.12 2004/10/04 01:10:59 steve
426 * Clean up spurious trailing white space.
428 * Revision 1.11 2003/02/09 23:33:26 steve
431 * Revision 1.10 2002/08/12 01:35:08 steve
432 * conditional ident string using autoconfig.
434 * Revision 1.9 2002/07/15 00:21:42 steve
435 * Fix initialization of symbol table string heap.
437 * Revision 1.8 2002/07/09 03:20:51 steve
438 * Fix split of root btree node.
440 * Revision 1.7 2002/07/05 04:40:59 steve
441 * Symbol table uses more efficient key string allocator,
442 * and remove all the symbol tables after compile is done.
444 * Revision 1.6 2002/07/05 02:50:58 steve
445 * Remove the vpi object symbol table after compile.
447 * Revision 1.5 2002/05/29 05:37:35 steve
448 * Use binary search to speed up deep lookups.
450 * Revision 1.4 2001/11/02 04:48:03 steve
451 * Implement split_node for symbol table (hendrik)
453 * Revision 1.3 2001/05/09 04:23:19 steve
454 * Now that the interactive debugger exists,
455 * there is no use for the output dump.
457 * Revision 1.2 2001/03/18 00:37:55 steve
458 * Add support for vpi scopes.
460 * Revision 1.1 2001/03/11 00:29:39 steve
461 * Add the vvp engine to cvs.