1 /*
2    Copyright (c) 1991-1999 Thomas T. Wetmore IV
3 
4    Permission is hereby granted, free of charge, to any person
5    obtaining a copy of this software and associated documentation
6    files (the "Software"), to deal in the Software without
7    restriction, including without limitation the rights to use, copy,
8    modify, merge, publish, distribute, sublicense, and/or sell copies
9    of the Software, and to permit persons to whom the Software is
10    furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be
13    included in all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22    SOFTWARE.
23 */
24 /*=============================================================
25  * table.c -- Provides a table container object
26  *  This provides type-safe tables
27  *  These tables are reference counted objects
28  *  This uses either hashtbl or rbtree for storage
29  *==============================================================*/
30 
31 #include "llstdlib.h"
32 #include "vtable.h"
33 #include "table.h"
34 #include "object.h"
35 #include "hashtab.h"
36 #include "rbtree.h"
37 #include "lloptions.h"
38 
39 /*********************************************
40  * local enums & defines
41  *********************************************/
42 
43 enum TB_VALTYPE
44 	{
45 		TB_NULL /* (not used) */
46 		, TB_INT /* table of integers */
47 		, TB_STR /* table of strings */
48 		, TB_HPTR /* table of heap pointers (table frees them) */
49 		, TB_VPTR /* table of void pointers (table does not free) */
50 		, TB_OBJ /* table of objects */
51 	};
52 
53 /*********************************************
54  * local types
55  *********************************************/
56 
57 /* table object itself */
58 struct tag_table {
59 	struct tag_vtable *vtable; /* generic object */
60 	INT refcnt; /* ref-countable object */
61 	enum TB_VALTYPE valtype;
62 	DELFUNC destroyfunc; /* how to destroy elements */
63 	HASHTAB hashtab;
64 	RBTREE rbtree;
65 };
66 /* typedef struct tag_table *TABLE */ /* in table.h */
67 
68 /* table iterator */
69 struct tag_table_iter {
70 	struct tag_vtable *vtable; /* generic object */
71 	INT refcnt; /* ref-countable object */
72 	HASHTAB_ITER hashtab_iter;
73 	RBITER rbit;
74 };
75 /* typedef struct tag_table_iter * TABLE_ITER; */ /* in table.h */
76 
77 /*********************************************
78  * local function prototypes
79  *********************************************/
80 
81 /* alphabetical */
82 static TABLE create_table_impl(enum TB_VALTYPE valtype, DELFUNC delfunc);
83 static void free_table_iter(TABLE_ITER tabit);
84 static VPTR get_rb_value(RBTREE rbtree, CNSTRING key);
85 static void * llalloc(size_t size);
86 static void llassert(int assertion, const char* error);
87 static int rbcompare(RBKEY key1, RBKEY key2);
88 static void rbdestroy(void * param, RBKEY key, RBVALUE info);
89 static void rbdestroy_value(TABLE tab, RBVALUE info);
90 static VPTR rb_valueof(RBTREE rbtree, CNSTRING key, BOOLEAN *there);
91 static void tabit_destructor(VTABLE *obj);
92 static void table_destructor(VTABLE *obj);
93 static void table_element_destructor(void * el);
94 static void table_element_obj_destructor(void *el);
95 
96 /*********************************************
97  * local variables
98  *********************************************/
99 
100 static struct tag_vtable vtable_for_table = {
101 	VTABLE_MAGIC
102 	, "table"
103 	, &table_destructor
104 	, &refcountable_isref
105 	, &refcountable_addref
106 	, &refcountable_release
107 	, 0 /* copy_fnc */
108 	, &generic_get_type_name
109 };
110 static struct tag_vtable vtable_for_tabit = {
111 	VTABLE_MAGIC
112 	, "table_iter"
113 	, &tabit_destructor
114 	, &refcountable_isref
115 	, &refcountable_addref
116 	, &refcountable_release
117 	, 0 /* copy_fnc */
118 	, &generic_get_type_name
119 };
120 
121 /*********************************************
122  * local & exported function definitions
123  * body of module
124  *********************************************/
125 
126 /*=============================
127  * init_table_module -- Module initialization
128  *===========================*/
129 void
init_table_module(void)130 init_table_module (void)
131 {
132 	/* Red/Black tree and stack modules need external assert & alloc handlers */
133 	RbInitModule(&llassert, &llalloc);
134 }
135 /*=============================
136  * create_table_impl -- Create table
137  * All tables are created in this function
138  * returns addref'd table
139  *===========================*/
140 static TABLE
create_table_impl(enum TB_VALTYPE valtype,DELFUNC delfunc)141 create_table_impl (enum TB_VALTYPE valtype, DELFUNC delfunc)
142 {
143 	TABLE tab = (TABLE) stdalloc(sizeof(*tab));
144 
145 	tab->vtable = &vtable_for_table;
146 	tab->refcnt = 1;
147 	tab->valtype = valtype;
148 	if (getlloptstr("rbtree", 0))
149 		tab->rbtree = RbTreeCreate(tab, rbcompare, rbdestroy);
150 	else
151 		tab->hashtab = create_hashtab();
152 	tab->destroyfunc = delfunc;
153 	return tab;
154 }
155 /*=============================
156  * create_table_int -- Create table holding integers
157  * returns addref'd table
158  *===========================*/
159 TABLE
create_table_int(void)160 create_table_int (void)
161 {
162 	return create_table_impl(TB_INT, table_element_destructor);
163 }
164 /*=============================
165  * create_table_str -- Create table holding heap strings
166  * (table dup & frees strings)
167  * returns addref'd table
168  *===========================*/
169 TABLE
create_table_str(void)170 create_table_str (void)
171 {
172 	return create_table_impl(TB_STR, table_element_destructor);
173 }
174 /*=============================
175  * create_table_hptr -- Create table holding heap pointers
176  * (ie, table will free elements)
177  * returns addref'd table
178  *===========================*/
179 TABLE
create_table_hptr(void)180 create_table_hptr (void)
181 {
182 	return create_table_impl(TB_HPTR, table_element_destructor);
183 }
184 /*=============================
185  * create_table_vptr -- Create table holding shared pointers
186  * (ie, table will not free elements)
187  * returns addref'd table
188  *===========================*/
189 TABLE
create_table_vptr(void)190 create_table_vptr (void)
191 {
192 	return create_table_impl(TB_VPTR, NULL);
193 }
194 /*=============================
195  * create_table_custom_vptr -- Create table holding pointers
196  * (table calls custom function to destroy elements)
197  * returns addref'd table
198  *===========================*/
199 TABLE
create_table_custom_vptr(void (* destroyel)(void * ptr))200 create_table_custom_vptr (void (*destroyel)(void *ptr))
201 {
202 	return create_table_impl(TB_VPTR, destroyel);
203 }
204 /*=============================
205  * create_table_obj -- Create table holding objects
206  * (ie, table will release them using release_object)
207  * returns addref'd table
208  *===========================*/
209 TABLE
create_table_obj(void)210 create_table_obj (void)
211 {
212 	return create_table_impl(TB_OBJ, table_element_obj_destructor);
213 }
214 /*=================================================
215  * destroy_table -- destroy all element & memory for table
216  *===============================================*/
217 void
destroy_table(TABLE tab)218 destroy_table (TABLE tab)
219 {
220 	if (!tab) return;
221 	ASSERT(tab->vtable == &vtable_for_table);
222 
223 	/* should not be called for a shared table */
224 	ASSERT(tab->refcnt==1 || tab->refcnt==0);
225 
226 	if (tab->rbtree)
227 		RbTreeDestroy(tab->rbtree);
228 	else
229 		destroy_hashtab(tab->hashtab, tab->destroyfunc);
230 	memset(tab, 0, sizeof(*tab));
231 	stdfree(tab);
232 }
233 /*=================================================
234  * table_destructor -- destructor for table
235  *  (destructor entry in vtable)
236  *===============================================*/
237 static void
table_destructor(VTABLE * obj)238 table_destructor (VTABLE *obj)
239 {
240 	TABLE tab = (TABLE)obj;
241 	destroy_table(tab);
242 }
243 /*=================================================
244  * table_element_destructor -- element destructor function
245  *  used for all pointer tables except TB_VPTR
246  *===============================================*/
247 static void
table_element_destructor(void * el)248 table_element_destructor (void * el)
249 {
250 	stdfree(el);
251 }
252 /*=================================================
253  * table_element_obj_destructor -- object element destructor function
254  *  used for object tables (TB_OBJ)
255  *===============================================*/
256 static void
table_element_obj_destructor(void * el)257 table_element_obj_destructor (void *el)
258 {
259 	if (el) {
260 		release_object(el);
261 	}
262 }
263 /*=================================================
264  * addref_table -- increment reference count of table
265  *===============================================*/
266 void
addref_table(TABLE tab)267 addref_table (TABLE tab)
268 {
269 	ASSERT(tab->vtable == &vtable_for_table);
270 	++tab->refcnt;
271 }
272 /*=================================================
273  * release_table -- decrement reference count of table
274  *  and free if appropriate (ref count hits zero)
275  *===============================================*/
276 void
release_table(TABLE tab)277 release_table (TABLE tab)
278 {
279 	if (!tab) return;
280 	ASSERT(tab->vtable == &vtable_for_table);
281 	--tab->refcnt;
282 	if (!tab->refcnt) {
283 		destroy_table(tab);
284 	}
285 }
286 /*======================================
287  * insert_table_int -- Insert key & INT value into table
288  *====================================*/
289 void
insert_table_int(TABLE tab,CNSTRING key,INT ival)290 insert_table_int (TABLE tab, CNSTRING key, INT ival)
291 {
292 	INT * newval = stdalloc(sizeof(*newval));
293 
294 	*newval = ival;
295 
296 	ASSERT(tab);
297 	ASSERT(tab->valtype == TB_INT);
298 
299 	insert_table_ptr(tab, key, newval);
300 }
301 /*======================================
302  * insert_table_str -- Insert key & string value into table
303  *====================================*/
304 void
insert_table_str(TABLE tab,CNSTRING key,CNSTRING value)305 insert_table_str (TABLE tab, CNSTRING key, CNSTRING value)
306 {
307 	insert_table_ptr(tab, key, strsave(value));
308 }
309 /*======================================
310  * insert_table_ptr -- Insert key & pointer value into table
311  *====================================*/
312 void
insert_table_ptr(TABLE tab,CNSTRING key,VPTR ptr)313 insert_table_ptr (TABLE tab, CNSTRING key, VPTR ptr)
314 {
315 	INT * oldval = 0;
316 
317 	ASSERT(tab);
318 	ASSERT(tab->vtable == &vtable_for_table);
319 
320 	if (tab->rbtree) {
321 		/* first see if key already exists, so we can just change value */
322 		RBNODE node = RbExactQuery(tab->rbtree, key);
323 		if (node) {
324 			VPTR oldptr = RbGetInfo(node);
325 			if (oldptr != ptr) {
326 				RbSetInfo(node, ptr);
327 				rbdestroy_value(tab, oldptr);
328 			}
329 			return;
330 		}
331 		RbTreeInsert(tab->rbtree, strsave(key), ptr);
332 	} else {
333 		oldval = insert_hashtab(tab->hashtab, key, ptr);
334 		if (oldval && tab->destroyfunc) {
335 			(*tab->destroyfunc)(oldval);
336 		}
337 	}
338 }
339 /*======================================
340  * insert_table_obj -- Insert key & object into table
341  * table addrefs the object
342  *====================================*/
343 void
insert_table_obj(TABLE tab,CNSTRING key,VPTR obj)344 insert_table_obj (TABLE tab, CNSTRING key, VPTR obj)
345 {
346 	if (obj)
347 		addref_object(obj);
348 	insert_table_ptr(tab, key, obj);
349 }
350 /*======================================
351  * replace_table_str -- Insert or replace
352  *  key & value
353  * Created: 2001/11/23, Perry Rapp
354  *====================================*/
355 void
replace_table_str(TABLE tab,CNSTRING key,CNSTRING str)356 replace_table_str (TABLE tab, CNSTRING key, CNSTRING str)
357 {
358 	/* insert function handles deleting old value */
359 	insert_table_str(tab, key, str);
360 }
361 /*==========================================
362  * delete_table_element -- Delete element from table
363  *  tab: [I/O]  table from which to remove element
364  *  key: [IN]   key to find element to remove
365  * Destroys key and value as appropriate
366  *========================================*/
367 void
delete_table_element(TABLE tab,CNSTRING key)368 delete_table_element (TABLE tab, CNSTRING key)
369 {
370 	void * oldval=0;
371 
372 	ASSERT(tab);
373 	ASSERT(tab->vtable == &vtable_for_table);
374 
375 	if (tab->rbtree) {
376 		RBNODE old = RbExactQuery(tab->rbtree, key);
377 		if (old)
378 			RbDeleteNode(tab->rbtree, old);
379 	} else {
380 		oldval = remove_hashtab(tab->hashtab, key);
381 		if (oldval && tab->destroyfunc) {
382 			(*tab->destroyfunc)(oldval);
383 		}
384 	}
385 }
386 /*======================================
387  * in_table() - Check for entry in table
388  *====================================*/
389 BOOLEAN
in_table(TABLE tab,CNSTRING key)390 in_table (TABLE tab, CNSTRING key)
391 {
392 	ASSERT(tab);
393 	ASSERT(tab->vtable == &vtable_for_table);
394 
395 	if (tab->rbtree) {
396 		return RbExactQuery(tab->rbtree, key) != 0;
397 	} else {
398 		return in_hashtab(tab->hashtab, key);
399 	}
400 }
401 /*===============================
402  * valueof_int -- Find int value of entry
403  * return 0 if missing
404  * Created: 2001/06/03 (Perry Rapp)
405  *=============================*/
406 INT
valueof_int(TABLE tab,CNSTRING key)407 valueof_int (TABLE tab, CNSTRING key)
408 {
409 	INT * val=0;
410 
411 	ASSERT(tab);
412 	ASSERT(tab->vtable == &vtable_for_table);
413 	ASSERT(tab->valtype == TB_INT);
414 
415 	if (tab->rbtree) {
416 		val = get_rb_value(tab->rbtree, key);
417 	} else {
418 		val = find_hashtab(tab->hashtab, key, NULL);
419 	}
420 	return (val ? *val : 0);
421 }
422 /*===============================
423  * valueof_str -- Find string value of entry
424  *=============================*/
425 STRING
valueof_str(TABLE tab,CNSTRING key)426 valueof_str (TABLE tab, CNSTRING key)
427 {
428 	ASSERT(tab);
429 	ASSERT(tab->vtable == &vtable_for_table);
430 	ASSERT(tab->valtype == TB_STR);
431 
432 	if (tab->rbtree) {
433 		return (STRING)get_rb_value(tab->rbtree, key);
434 	} else {
435 		return (STRING)find_hashtab(tab->hashtab, key, NULL);
436 	}
437 
438 
439 }
440 /*===============================
441  * valueof_ptr -- Find pointer value of entry
442  *=============================*/
443 VPTR
valueof_ptr(TABLE tab,CNSTRING key)444 valueof_ptr (TABLE tab, CNSTRING key)
445 {
446 	ASSERT(tab);
447 	ASSERT(tab->vtable == &vtable_for_table);
448 	ASSERT(tab->valtype == TB_HPTR || tab->valtype == TB_VPTR);
449 
450 	if (tab->rbtree) {
451 		return (STRING)get_rb_value(tab->rbtree, key);
452 	} else {
453 		return find_hashtab(tab->hashtab, key, NULL);
454 	}
455 }
456 /*===============================
457  * valueof_obj -- Find object value of entry
458  *=============================*/
459 VPTR
valueof_obj(TABLE tab,CNSTRING key)460 valueof_obj (TABLE tab, CNSTRING key)
461 {
462 	ASSERT(tab);
463 	ASSERT(tab->vtable == &vtable_for_table);
464 	ASSERT(tab->valtype == TB_OBJ);
465 
466 	if (tab->rbtree) {
467 		return get_rb_value(tab->rbtree, key);
468 	} else {
469 		return find_hashtab(tab->hashtab, key, NULL);
470 	}
471 }
472 /*===================================
473  * valueofbool_int -- Find pointer value of entry
474  * BOOLEAN *there:   [OUT] FALSE if not found
475  *=================================*/
476 INT
valueofbool_int(TABLE tab,CNSTRING key,BOOLEAN * there)477 valueofbool_int (TABLE tab, CNSTRING key, BOOLEAN *there)
478 {
479 	INT * val=0;
480 
481 	ASSERT(tab);
482 	ASSERT(tab->vtable == &vtable_for_table);
483 	ASSERT(tab->valtype == TB_INT);
484 
485 	if (tab->rbtree) {
486 		val = (INT *)rb_valueof(tab->rbtree, key, there);
487 	} else {
488 		val = find_hashtab(tab->hashtab, key, there);
489 	}
490 	return val ? *val : 0;
491 }
492 /*===================================
493  * valueofbool_str -- Find string value of entry
494  * BOOLEAN *there:   [OUT] FALSE if not found
495  *=================================*/
496 STRING
valueofbool_str(TABLE tab,CNSTRING key,BOOLEAN * there)497 valueofbool_str (TABLE tab, CNSTRING key, BOOLEAN *there)
498 {
499 	ASSERT(tab);
500 	ASSERT(tab->vtable == &vtable_for_table);
501 	ASSERT(tab->valtype == TB_STR);
502 
503 	if (tab->rbtree) {
504 		return rb_valueof(tab->rbtree, key, there);
505 	} else {
506 		return (STRING)find_hashtab(tab->hashtab, key, there);
507 	}
508 }
509 /*===================================
510  * valueofbool_ptr -- Find pointer value of entry
511  * BOOLEAN *there:   [OUT] FALSE if not found
512  *=================================*/
513 VPTR
valueofbool_ptr(TABLE tab,CNSTRING key,BOOLEAN * there)514 valueofbool_ptr (TABLE tab, CNSTRING key, BOOLEAN *there)
515 {
516 	ASSERT(tab);
517 	ASSERT(tab->vtable == &vtable_for_table);
518 	ASSERT(tab->valtype == TB_HPTR || tab->valtype == TB_VPTR);
519 
520 	if (tab->rbtree) {
521 		return rb_valueof(tab->rbtree, key, there);
522 	} else {
523 		return find_hashtab(tab->hashtab, key, there);
524 	}
525 }
526 /*===================================
527  * valueofbool_obj -- Find object value of entry
528  * BOOLEAN *there:   [OUT] FALSE if not found
529  *=================================*/
530 VPTR
valueofbool_obj(TABLE tab,CNSTRING key,BOOLEAN * there)531 valueofbool_obj (TABLE tab, CNSTRING key, BOOLEAN *there)
532 {
533 	ASSERT(tab);
534 	ASSERT(tab->vtable == &vtable_for_table);
535 	ASSERT(tab->valtype == TB_OBJ);
536 
537 	if (tab->rbtree) {
538 		return rb_valueof(tab->rbtree, key, there);
539 	} else {
540 		return find_hashtab(tab->hashtab, key, there);
541 	}
542 }
543 /*=================================================
544  * begin_table_iter -- Begin iteration of table
545  *  returns addref'd iterator object
546  *===============================================*/
547 TABLE_ITER
begin_table_iter(TABLE tab)548 begin_table_iter (TABLE tab)
549 {
550 	TABLE_ITER tabit = (TABLE_ITER)stdalloc(sizeof(*tabit));
551 	++tabit->refcnt;
552 	if (tab->rbtree) {
553 		tabit->rbit = RbBeginIter(tab->rbtree, 0, 0);
554 	} else {
555 		tabit->hashtab_iter = begin_hashtab(tab->hashtab);
556 	}
557 	return tabit;
558 }
559 /*=================================================
560  * next_table_ptr -- Advance to next pointer in table
561  * skips over any other types of table elements
562  * returns FALSE if runs out of table elements
563  *===============================================*/
564 BOOLEAN
next_table_ptr(TABLE_ITER tabit,CNSTRING * pkey,VPTR * pptr)565 next_table_ptr (TABLE_ITER tabit, CNSTRING *pkey, VPTR *pptr)
566 {
567 	if (tabit->rbit)
568 		return RbNext(tabit->rbit, (RBKEY *)pkey, pptr);
569 	else
570 		return next_hashtab(tabit->hashtab_iter, pkey, pptr);
571 }
572 /*=================================================
573  * next_table_int -- Advance to next int in table
574  * skips over any other types of table elements
575  * returns FALSE if runs out of table elements
576  *===============================================*/
577 BOOLEAN
next_table_int(TABLE_ITER tabit,CNSTRING * pkey,INT * pival)578 next_table_int (TABLE_ITER tabit, CNSTRING *pkey, INT * pival)
579 {
580 	VPTR val=0;
581 	if (tabit->rbit) {
582 		if (!RbNext(tabit->rbit, (RBKEY *)pkey, &val))
583 			return FALSE;
584 	} else {
585 		if (!next_hashtab(tabit->hashtab_iter, pkey, &val))
586 			return FALSE;
587 	}
588 
589 	*pival = *(INT *)val;
590 	return TRUE;
591 }
592 /*=================================================
593  * end_table_iter -- Release reference to table iterator object
594  *===============================================*/
595 void
end_table_iter(TABLE_ITER * ptabit)596 end_table_iter (TABLE_ITER * ptabit)
597 {
598 	ASSERT(ptabit);
599 	ASSERT(*ptabit);
600 	--(*ptabit)->refcnt;
601 	if (!(*ptabit)->refcnt) {
602 		free_table_iter(*ptabit);
603 	}
604 	*ptabit = 0;
605 }
606 /*=================================================
607  * free_table_iter -- Delete & free table iterator object
608  *===============================================*/
609 static void
free_table_iter(TABLE_ITER tabit)610 free_table_iter (TABLE_ITER tabit)
611 {
612 	if (!tabit) return;
613 	ASSERT(!tabit->refcnt);
614         if (!tabit->rbit) {
615                 end_hashtab(&tabit->hashtab_iter);
616 	}
617 	memset(tabit, 0, sizeof(*tabit));
618 	stdfree(tabit);
619 }
620 /*=================================================
621  * get_table_count -- Return #elements
622  * Created: 2002/02/17, Perry Rapp
623  *===============================================*/
624 INT
get_table_count(TABLE tab)625 get_table_count (TABLE tab)
626 {
627 	if (!tab) return 0;
628 
629 	ASSERT(tab->vtable == &vtable_for_table);
630 
631 	if (tab->rbtree)
632 		return RbGetCount(tab->rbtree);
633 	else
634 		return get_hashtab_count(tab->hashtab);
635 }
636 /*=================================================
637  * copy_table -- Copy all elements from src to dest
638  *===============================================*/
639 void
copy_table(const TABLE src,TABLE dest)640 copy_table (const TABLE src, TABLE dest)
641 {
642 	if (!src || !dest) return;
643 
644 	ASSERT(src->vtable == &vtable_for_table);
645 	ASSERT(dest->vtable == &vtable_for_table);
646 
647 	if (src->valtype == TB_INT) {
648 		TABLE_ITER tabit = begin_table_iter(src);
649 		CNSTRING key=0;
650 		INT ival=0;
651 		ASSERT(dest->valtype == TB_INT);
652 		while (next_table_int(tabit, &key, &ival)) {
653 			insert_table_int(dest, key, ival);
654 		}
655 		end_table_iter(&tabit);
656 		return;
657 	}
658 
659 	if (src->valtype == TB_STR) {
660 		TABLE_ITER tabit = begin_table_iter(src);
661 		CNSTRING key=0;
662 		VPTR val=0;
663 		ASSERT(dest->valtype == src->valtype);
664 		while (next_table_ptr(tabit, &key, &val)) {
665 			insert_table_str(dest, key, val);
666 		}
667 		end_table_iter(&tabit);
668 		return;
669 	}
670 
671 	if (src->valtype == TB_HPTR) {
672 		ASSERT(0);
673 	}
674 
675 	if (src->valtype == TB_VPTR) {
676 		TABLE_ITER tabit = begin_table_iter(src);
677 		CNSTRING key=0;
678 		VPTR val=0;
679 		ASSERT(dest->valtype == src->valtype);
680 		while (next_table_ptr(tabit, &key, &val)) {
681 			insert_table_ptr(dest, key, val);
682 		}
683 		end_table_iter(&tabit);
684 		return;
685 	}
686 
687 	if (src->valtype == TB_OBJ) {
688 		TABLE_ITER tabit = begin_table_iter(src);
689 		CNSTRING key=0;
690 		VPTR val=0;
691 		ASSERT(dest->valtype == src->valtype);
692 		while (next_table_ptr(tabit, &key, &val)) {
693 			addref_object(val);
694 			insert_table_obj(dest, key, val);
695 		}
696 		end_table_iter(&tabit);
697 		return;
698 	}
699 
700 	ASSERT(0);
701 }
702 /*=================================================
703  * tabit_destructor -- destructor for table iterator
704  *  (vtable destructor)
705  *===============================================*/
706 static void
tabit_destructor(VTABLE * obj)707 tabit_destructor (VTABLE *obj)
708 {
709 	TABLE_ITER tabit = (TABLE_ITER)obj;
710 	ASSERT(tabit->vtable == &vtable_for_tabit);
711 	free_table_iter(tabit);
712 }
713 /*=================================================
714  * increment_table_int -- increment an integer element value
715  * set to 1 if not found
716  *===============================================*/
717 void
increment_table_int(TABLE tab,CNSTRING key)718 increment_table_int (TABLE tab, CNSTRING key)
719 {
720 	BOOLEAN found=FALSE;
721 	INT value = valueofbool_int(tab, key, &found);
722 	if (found) {
723 		insert_table_int(tab, key, value+1);
724 	} else {
725 		insert_table_int(tab, key, 1);
726 	}
727 }
728 /*=================================================
729  * llassert -- Implement assertion
730  *  (for rbtree module, which does not include lifelines headers)
731  *===============================================*/
732 static void
llassert(int assertion,const char * error)733 llassert (int assertion, const char* error)
734 {
735 	if (assertion)
736 		return;
737 	FATAL2(error);
738 }
739 /*=================================================
740  * llalloc -- Implement alloc
741  *  (for rbtree module, which does not include lifelines headers)
742  *===============================================*/
743 static void *
llalloc(size_t size)744 llalloc (size_t size)
745 {
746 	return stdalloc(size);
747 }
748 /*=================================================
749  * rbcompare -- compare two rbtree keys
750  *  (for rbtree module, which treats keys as opaque)
751  *===============================================*/
752 static int
rbcompare(RBKEY key1,RBKEY key2)753 rbcompare (RBKEY key1, RBKEY key2)
754 {
755 	return cmpstrloc(key1, key2);
756 }
757 /*=================================================
758  * rbdestroy -- Destructor for key & value of rbtree
759  *  (for rbtree module, which does not manage key or value memory)
760  *===============================================*/
761 static void
rbdestroy(void * param,RBKEY key,RBVALUE info)762 rbdestroy (void * param, RBKEY key, RBVALUE info)
763 {
764 	stdfree((void *)key);
765 	rbdestroy_value((TABLE)param, info);
766 }
767 /*=================================================
768  * rbdestroy_value -- Destroy value stored in rbtree
769  *  (for rbtree module, which does not manage key or value memory)
770  *===============================================*/
771 static void
rbdestroy_value(TABLE tab,RBVALUE info)772 rbdestroy_value (TABLE tab, RBVALUE info)
773 {
774 	if (tab->destroyfunc) {
775 		(*tab->destroyfunc)(info);
776 		return;
777 	}
778 	switch(tab->valtype) {
779 	case TB_INT:
780 	case TB_STR:
781 	case TB_HPTR:
782 		table_element_destructor(info);
783 		break;
784 	case TB_OBJ:
785 		table_element_obj_destructor(info);
786 	case TB_NULL:
787 	case TB_VPTR:
788 	        ;
789 	}
790 }
791 /*=================================================
792  * get_rb_value -- Shortcut fetch of value from rbtree key
793  *===============================================*/
794 static VPTR
get_rb_value(RBTREE rbtree,CNSTRING key)795 get_rb_value (RBTREE rbtree, CNSTRING key)
796 {
797 	RBNODE node = RbExactQuery(rbtree, key);
798 	return node ? RbGetInfo(node) : 0;
799 }
800 /*=================================================
801  * rb_valueof -- Get value & set *there to indicate presence
802  *===============================================*/
803 static VPTR
rb_valueof(RBTREE rbtree,CNSTRING key,BOOLEAN * there)804 rb_valueof (RBTREE rbtree, CNSTRING key, BOOLEAN *there)
805 {
806 	RBNODE node = RbExactQuery(rbtree, key);
807 	if (there)
808 		*there = !!node;
809 	return node ? RbGetInfo(node) : 0;
810 }
811