1 /*
2    Copyright (c) 1991-1999 Thomas T. Wetmore IV
3    "The MIT license"
4    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7 */
8 /*=============================================================
9  * list.c -- Doubly-linked list data type
10  * Copyright(c) 1991-94 by T.T. Wetmore IV; all rights reserved
11  *===========================================================*/
12 
13 #include "standard.h"
14 #include "llstdlib.h"
15 #include "vtable.h"
16 
17 /*********************************************
18  * local types
19  *********************************************/
20 
21 
22 /* list object itself */
23 struct tag_list {
24 	/* a LIST is an OBJECT */
25 	struct tag_vtable * vtable; /* generic object table (see vtable.h) */
26 	INT l_refcnt; /* reference counted object */
27 	LNODE l_head;
28 	LNODE l_tail;
29 	INT l_len;
30 	INT l_type;
31 	ELEMENT_DESTRUCTOR l_del_element;
32 };
33 /* typedef struct tag_list *LIST; */ /* in list.h */
34 
35 /* list iterator */
36 struct tag_list_iter {
37 	struct tag_vtable *vtable; /* generic object */
38 	INT refcnt; /* ref-countable object */
39 	LNODE current;
40 	LIST list;
41 	INT status; /* 1=forward, 1=reverse, 0=EOF */
42 };
43 /* typedef struct tag_list_iter * LIST_ITER; */ /* in list.h */
44 
45 /*********************************************
46  * local enums & defines
47  *********************************************/
48 
49 #define ltype(l)   ((l)->l_type)
50 #define lhead(l)   ((l)->l_head)
51 #define ltail(l)   ((l)->l_tail)
52 #define llen(l)    ((l)->l_len)
53 
54 /*********************************************
55  * local function prototypes
56  *********************************************/
57 
58 /* alphabetical */
59 static void free_list_element(VPTR vptr);
60 static void free_list_iter(LIST_ITER listit);
61 static void list_destructor(VTABLE *obj);
62 static void listit_destructor(VTABLE *obj);
63 void make_list_empty_impl(LIST list, ELEMENT_DESTRUCTOR func);
64 static LNODE nth_in_list_from_tail(LIST list, INT index1b, BOOLEAN createels
65 	, LIST_CREATE_VALUE createfnc);
66 static void validate_list(LIST list);
67 
68 /*********************************************
69  * local variables
70  *********************************************/
71 
72 static struct tag_vtable vtable_for_list = {
73 	VTABLE_MAGIC
74 	, "list"
75 	, &list_destructor
76 	, &refcountable_isref
77 	, &refcountable_addref
78 	, &refcountable_release
79 	, 0 /* copy_fnc */
80 	, &generic_get_type_name
81 };
82 static struct tag_vtable vtable_for_listit = {
83 	VTABLE_MAGIC
84 	, "list_iter"
85 	, &listit_destructor
86 	, &refcountable_isref
87 	, &refcountable_addref
88 	, &refcountable_release
89 	, 0 /* copy_fnc */
90 	, &generic_get_type_name
91 };
92 
93 /*===========================
94  * create_list_impl -- Create list
95  * returns addref'd list
96  *=========================*/
97 static LIST
create_list_impl(void)98 create_list_impl (void)
99 {
100 	LIST list = (LIST) stdalloc(sizeof(*list));
101 	memset(list, 0, sizeof(*list));
102 	list->vtable = &vtable_for_list;
103 	list->l_refcnt = 1;
104 	ltype(list) = LISTNOFREE;
105 	lhead(list) = ltail(list) = NULL;
106 	llen(list) = 0;
107 	validate_list(list);
108 	return list;
109 }
110 /*===========================
111  * create_list -- Create list (LISTNOFREE)
112  * returns addref'd list
113  *=========================*/
114 LIST
create_list(void)115 create_list (void)
116 {
117 	return create_list2(LISTNOFREE);
118 }
119 /*===========================
120  * create_list2 -- Create list, with free type
121  * returns addref'd list
122  *=========================*/
123 LIST
create_list2(INT whattofree)124 create_list2 (INT whattofree)
125 {
126 	LIST list = create_list_impl();
127 	ltype(list) = whattofree;
128 	return list;
129 }
130 /*===========================
131  * create_list3 -- Create list, with element destructor
132  * returns addref'd list
133  *=========================*/
134 LIST
create_list3(ELEMENT_DESTRUCTOR func)135 create_list3 (ELEMENT_DESTRUCTOR func)
136 {
137 	LIST list = create_list_impl();
138 	list->l_del_element = func;
139 	return list;
140 }
141 /*===========================
142  * destroy_list -- Delete all elements & destroy list
143  *  list: [IN]  list to completely delete
144  *=========================*/
145 void
destroy_list(LIST list)146 destroy_list (LIST list)
147 {
148 	if (!list) return;
149 	ASSERT(list->vtable == &vtable_for_list);
150 	make_list_empty_impl(list, NULL);
151 	destroy_empty_list(list);
152 }
153 /*===========================
154  * destroy_empty_list -- Destroy a list with no elements
155  *  ASSERT check that list is in fact empty
156  *=========================*/
157 void
destroy_empty_list(LIST list)158 destroy_empty_list (LIST list)
159 {
160 	if (!list) return;
161 	ASSERT(list->vtable == &vtable_for_list);
162 	ASSERT(llen(list) == 0);
163 	stdfree(list);
164 }
165 /*===========================
166  * in_list -- find first element returning true from check function
167  *  list: [IN]  list to search
168  *  el:   [IN]  parameter to pass thru to check function
169  *  func: [IN]  check function
170  * Calls check function on each element in turn until one returns TRUE
171  * Returns index of element found, or -1 if none pass check
172  *=========================*/
173 INT
in_list(LIST list,VPTR param,BOOLEAN (* func)(VPTR param,VPTR el))174 in_list (LIST list, VPTR param, BOOLEAN (*func)(VPTR param, VPTR el))
175 {
176 	LNODE lnode;
177 	INT index=0;
178 	if (is_empty_list(list)) /* calls validate_list */
179 		return -1;
180 	lnode = lhead(list);
181 	while (lnode) {
182 		if ((*func)(param, lelement(lnode)))
183 			return index;
184 		lnode = lnext(lnode);
185 	}
186 	validate_list(list);
187 	return -1;
188 }
189 /*===================================
190  * free_list_element -- Simple heap element destructor
191  *=================================*/
192 static void
free_list_element(VPTR vptr)193 free_list_element (VPTR vptr)
194 {
195 	if (vptr) stdfree(vptr);
196 }
197 /*===================================
198  * make_list_empty_impl -- Make list empty
199  *=================================*/
200 void
make_list_empty_impl(LIST list,ELEMENT_DESTRUCTOR func)201 make_list_empty_impl (LIST list, ELEMENT_DESTRUCTOR func)
202 {
203 	LNODE lnode0, lnode;
204 
205 	if (!list) return;
206 
207 	if (!func)
208 		func = list->l_del_element;
209 	if (!func) {
210 		if (ltype(list) == LISTDOFREE)
211 			func = &free_list_element;
212 	}
213 
214 	lnode0 = lhead(list);
215 	while (lnode0) {
216 		lnode = lnext(lnode0);
217 		if (func) (*func)(lelement(lnode0));
218 		stdfree(lnode0);
219 		lnode0 = lnode;
220 	}
221 	lhead(list) = ltail(list) = NULL;
222 	llen(list) = 0;
223 	/* no effect on refcount */
224 	validate_list(list);
225 }
226 /*===================================
227  * make_list_empty -- Make list empty
228  *=================================*/
229 void
make_list_empty(LIST list)230 make_list_empty (LIST list)
231 {
232 	make_list_empty_impl(list, NULL);
233 }
234 /*===================================
235  * is_empty_list -- Check for empty list
236  *  list:  [IN]  list
237  *=================================*/
238 BOOLEAN
is_empty_list(const LIST list)239 is_empty_list (const LIST list)
240 {
241 	validate_list(list);
242 	return !list || !llen(list);
243 }
244 /*==================================
245  * push_list -- Push element on head of list
246  *  list:  [I/O]  list
247  *  el:    [IN]   new element
248  *================================*/
249 void
push_list(LIST list,VPTR el)250 push_list (LIST list, VPTR el)
251 {
252 	LNODE node = NULL;
253 
254 	if (!list) return;
255 	node = (LNODE) stdalloc(sizeof(*node));
256 	lelement(node) = el;
257 	if (is_empty_list(list)) {
258 		lprev(node) = lnext(node) = NULL;
259 		lhead(list) = ltail(list) = node;
260 	} else {
261 		lnext(node) = lhead(list);
262 		lprev(lhead(list)) = node;
263 		lprev(node) = NULL;
264 		lhead(list) = node;
265 	}
266 	++llen(list);
267 	validate_list(list);
268 }
269 /*=========================================
270  * back_list -- Put element on tail of list
271  *  list:  [I/O]  list
272  *  el:    [IN]   new element
273  *=======================================*/
274 void
back_list(LIST list,VPTR el)275 back_list (LIST list, VPTR el)
276 {
277 	LNODE node = NULL;
278 
279 	if (!list) return;
280 	node = (LNODE) stdalloc(sizeof(*node));
281 	lelement(node) = el;
282 	if (is_empty_list(list)) {
283 		lprev(node) = lnext(node) = NULL;
284 		lhead(list) = ltail(list) = node;
285 	} else {
286 		lprev(node) = ltail(list);
287 		lnext(ltail(list)) = node;
288 		lnext(node) = NULL;
289 		ltail(list) = node;
290 	}
291 	++llen(list);
292 	validate_list(list);
293 }
294 /*==================================
295  * pop_list -- Pop element from head of list
296  *  list:  [I/O]  list
297  *================================*/
298 VPTR
pop_list(LIST list)299 pop_list (LIST list)
300 {
301 	LNODE node;
302 	VPTR el;
303 	if (is_empty_list(list)) /* calls validate_list */
304 		return NULL;
305 	node = lhead(list);
306 	lhead(list) = lnext(node);
307 	if (!lhead(list))
308 		ltail(list) = NULL;
309 	else
310 		lprev(lhead(list)) = NULL;
311 	el = lelement(node);
312 	stdfree(node);
313 	--llen(list);
314 	validate_list(list);
315 	return el;
316 }
317 /*========================================
318  * validate_list -- Verify list ends don't disagree
319  *======================================*/
320 static void
validate_list(LIST list)321 validate_list (LIST list)
322 {
323 #ifdef LIST_ASSERTS
324 	ASSERT(!list || (lhead(list)&&ltail(list)) || (!lhead(list)&&!ltail(list)));
325 #else
326 	list=list; /* unused */
327 #endif
328 }
329 /*========================================
330  * enqueue_list -- Enqueue element on head of list
331  *======================================*/
332 void
enqueue_list(LIST list,VPTR el)333 enqueue_list (LIST list, VPTR el)
334 {
335 	push_list(list, el);
336 }
337 /*==========================================
338  * dequeue_list -- Dequeue element from tail of list
339  *========================================*/
340 VPTR
dequeue_list(LIST list)341 dequeue_list (LIST list)
342 {
343 	return pop_list_tail(list);
344 }
345 /*==========================================
346  * pop_list_tail -- Pop element from tail of list
347  *========================================*/
348 VPTR
pop_list_tail(LIST list)349 pop_list_tail (LIST list)
350 {
351 	LNODE node;
352 	VPTR el;
353 	if (is_empty_list(list)) /* calls validate_list */
354 		return NULL;
355 	node = ltail(list);
356 	ltail(list) = lprev(node);
357 	if (!ltail(list))
358 		lhead(list) = NULL;
359 	else
360 		lnext(ltail(list)) = NULL;
361 	el = lelement(node);
362 	stdfree(node);
363 	--llen(list);
364 	validate_list(list);
365 	return el;
366 }
367 /*=================================================
368  * nth_in_list_from_tail -- Find nth node in list, relative 1
369  *  start at tail & count towards head
370  *  createels is FALSE if caller does not want elements added (delete_list_element)
371  *===============================================*/
372 static LNODE
nth_in_list_from_tail(LIST list,INT index1b,BOOLEAN createels,LIST_CREATE_VALUE createfnc)373 nth_in_list_from_tail (LIST list, INT index1b, BOOLEAN createels, LIST_CREATE_VALUE createfnc)
374 {
375 	if (!list) return NULL;
376 	validate_list(list);
377 	/* handle reverse indices */
378 	if (index1b < 1) index1b += llen(list);
379 	/* null if out of bounds */
380 	if (index1b < 1) return NULL;
381 	if (index1b < llen(list)/2) {
382 		/* want element in back half, so count back from tail */
383 		LNODE node = ltail(list);
384 		INT i = index1b;
385 		while (--i) {
386 			node = lprev(node);
387 		}
388 		return node;
389 	} else if (index1b <= llen(list)) {
390 		/* want element in front half, so count forward from head */
391 		LNODE node = lhead(list);
392 		INT i = llen(list) + 1 - index1b;
393 		while (--i) {
394 			node = lnext(node);
395 		}
396 		return node;
397 	} else if (createels) {
398 		/* want element beyond end, so add as required */
399 		INT i = index1b + 1 - llen(list);
400 		while (--i) {
401 			VPTR newv = createfnc ? (*createfnc)(list) : NULL;
402 			enqueue_list(list, newv);
403 		}
404 		validate_list(list);
405 		return lhead(list);
406 	} else {
407 		/* element beyond but caller said not to create */
408 		return NULL;
409 	}
410 }
411 /*==================================================
412  * set_list_element - Set element using array access
413  *================================================*/
414 void
set_list_element(LIST list,INT index1b,VPTR val,LIST_CREATE_VALUE createfnc)415 set_list_element (LIST list, INT index1b, VPTR val, LIST_CREATE_VALUE createfnc)
416 {
417 	LNODE node = NULL;
418 	BOOLEAN createels = TRUE;
419 	if (!list) return;
420 	node = nth_in_list_from_tail(list, index1b, createels, createfnc);
421 	if (!node) return;
422 	lelement(node) = val;
423 	validate_list(list);
424 }
425 /*=======================================================
426  * get_list_element - Retrieve element using array access
427  *=====================================================*/
428 VPTR
get_list_element(LIST list,INT index1b,LIST_CREATE_VALUE createfnc)429 get_list_element (LIST list, INT index1b, LIST_CREATE_VALUE createfnc)
430 {
431 	LNODE node = NULL;
432 	BOOLEAN createels = TRUE;
433 	if (!list) return 0;
434 	node = nth_in_list_from_tail(list, index1b, createels, createfnc);
435 	if (!node) return 0;
436 	return lelement(node);
437 }
438 /*==================================
439  * length_list -- Return list length
440  *================================*/
441 INT
length_list(LIST list)442 length_list (LIST list)
443 {
444 	return !list ? 0 : llen(list);
445 }
446 /*=======================================================
447  * peek_list_head - Retrieve head element without removing it
448  *=====================================================*/
449 VPTR
peek_list_head(LIST list)450 peek_list_head (LIST list)
451 {
452 	LNODE node;
453 	if (!list) return 0;
454 	node = lhead(list);
455 	if (!node) return 0;
456 	return lelement(node);
457 }
458 /*=================================================
459  * create_list_iter -- Create new list iterator
460  *===============================================*/
461 static LIST_ITER
create_list_iter(LIST list)462 create_list_iter (LIST list)
463 {
464 	LIST_ITER listit = (LIST_ITER)stdalloc(sizeof(*listit));
465 	memset(listit, 0, sizeof(*listit));
466 	listit->list = list;
467 	listit->refcnt = 1;
468 	return listit;
469 }
470 /*=================================================
471  * begin_list -- Begin iteration of list
472  *===============================================*/
473 LIST_ITER
begin_list(LIST list)474 begin_list (LIST list)
475 {
476 	LIST_ITER listit = create_list_iter(list);
477 	/* current=0 is signal to next_list_element that we're starting */
478 	listit->status = (lhead(listit->list) ? 1 : 0);
479 	return listit;
480 }
481 /*=================================================
482  * begin_list_rev -- Begin reverse iteration of list
483  *===============================================*/
484 LIST_ITER
begin_list_rev(LIST list)485 begin_list_rev (LIST list)
486 {
487 	LIST_ITER listit = create_list_iter(list);
488 	/* current=0 is signal to next_list_element that we're starting */
489 	listit->status = (ltail(listit->list) ? -1 : 0);
490 	return listit;
491 }
492 /*=================================================
493  * next_element -- Find next element in list (iterating)
494  *===============================================*/
495 static BOOLEAN
next_list_element(LIST_ITER listit)496 next_list_element (LIST_ITER listit)
497 {
498 	if (!listit->status)
499 		return FALSE;
500 	if (!listit->current) {
501 		/* beginning */
502 		if (listit->status > 0)
503 			listit->current = lhead(listit->list);
504 		else
505 			listit->current = ltail(listit->list);
506 	} else {
507 		unlock_list_node(listit->current);
508 		if (listit->status > 0)
509 			listit->current = lnext(listit->current);
510 		else
511 			listit->current = lprev(listit->current);
512 	}
513 	if (listit->current)
514 		lock_list_node(listit->current);
515 	else
516 		listit->status = 0;
517 	return !!listit->status;
518 }
519 /*=================================================
520  * next_list_ptr -- Iterating list with pointers
521  *===============================================*/
522 BOOLEAN
next_list_ptr(LIST_ITER listit,VPTR * pptr)523 next_list_ptr (LIST_ITER listit, VPTR *pptr)
524 {
525 	if (!next_list_element(listit)) {
526 		*pptr = 0;
527 		return FALSE;
528 	}
529 	*pptr = lelement(listit->current);
530 	return TRUE;
531 }
532 /*=================================================
533  * change_list_ptr -- User changing pointer during iteration
534  *===============================================*/
535 BOOLEAN
change_list_ptr(LIST_ITER listit,VPTR newptr)536 change_list_ptr (LIST_ITER listit, VPTR newptr)
537 {
538 	if (!listit || !listit->current)
539 		return FALSE;
540 	lelement(listit->current) = newptr;
541 	return TRUE;
542 }
543 /*=================================================
544  * end_list_iter -- Release reference to list iterator object
545  *===============================================*/
546 void
end_list_iter(LIST_ITER * plistit)547 end_list_iter (LIST_ITER * plistit)
548 {
549 	ASSERT(plistit);
550 	ASSERT(*plistit);
551 	--(*plistit)->refcnt;
552 	if (!(*plistit)->refcnt) {
553 		free_list_iter(*plistit);
554 	}
555 	*plistit = 0;
556 }
557 /*=================================================
558  * free_list_iter -- Delete & free table iterator object
559  *===============================================*/
560 static void
free_list_iter(LIST_ITER listit)561 free_list_iter (LIST_ITER listit)
562 {
563 	if (!listit) return;
564 	ASSERT(!listit->refcnt);
565 	memset(listit, 0, sizeof(*listit));
566 	stdfree(listit);
567 }
568 /*=================================================
569  * lock_list_node -- Increment node lock count
570  *===============================================*/
571 void
lock_list_node(LNODE node)572 lock_list_node (LNODE node)
573 {
574 	++llocks(node);
575 }
576 /*=================================================
577  * unlock_list_node -- Decrement node lock count
578  *===============================================*/
579 void
unlock_list_node(LNODE node)580 unlock_list_node (LNODE node)
581 {
582 	--llocks(node);
583 	ASSERT(llocks(node) >= 0);
584 }
585 /*==================================================
586  * delete_list_element - Delete element using array access
587  *  Call func (unless NULL) on element before deleting
588  *================================================*/
589 #ifdef UNUSED_CODE
590 BOOLEAN
delete_list_element(LIST list,INT index1b,ELEMENT_DESTRUCTOR func)591 delete_list_element (LIST list, INT index1b, ELEMENT_DESTRUCTOR func)
592 {
593 	LNODE node = NULL;
594 	BOOLEAN createels = FALSE;
595 	if (!list) return FALSE;
596 	node = nth_in_list_from_tail(list, index1b, createels, 0);
597 	if (!node) return FALSE;
598 	if (llocks(node)) return FALSE;
599 	if (llen(list) == 1) {
600 		/* removing last element of list */
601 		llen(list) = 0;
602 		lhead(list) = ltail(list) = 0;
603 		if (func)
604 			(*func)(lelement(node));
605 		stdfree(node);
606 		return TRUE;
607 	}
608 	detach_node_from_list(list, node);
609 	return TRUE;
610 }
611 #endif
612 /*==================================================
613  * detach_node_from_list - Remove node from list
614  *  does not delete node, simply detaches it from the list
615  *  and decrements list's count
616  *================================================*/
617 static void
detach_node_from_list(LIST list,LNODE node)618 detach_node_from_list (LIST list, LNODE node)
619 {
620 	validate_list(list);
621 	if (lprev(node)) {
622 		lnext(lprev(node)) = lnext(node);
623 	}
624 	if (lnext(node)) {
625 		lprev(lnext(node)) = lprev(node);
626 	}
627 	if (lhead(list) == node) {
628 		lhead(list) = lnext(node);
629 	}
630 	if (ltail(list) == node) {
631 		ltail(list) = lprev(node);
632 	}
633 	--llen(list);
634 	validate_list(list);
635 }
636 /*==================================================
637  * find_delete_list_elements - Delete qualifying element(s)
638  *  list:      [I/O] list to change
639  *  func:      [IN]  test function to qualify elements (return TRUE to choose)
640  *  deleteall: [IN]  true to delete all qualifying, false to delete first
641  * returns number elements deleted
642  *================================================*/
643 INT
find_delete_list_elements(LIST list,VPTR param,BOOLEAN (* func)(VPTR param,VPTR el),BOOLEAN deleteall)644 find_delete_list_elements (LIST list, VPTR param,
645 	BOOLEAN (*func)(VPTR param, VPTR el), BOOLEAN deleteall)
646 {
647 	LNODE lnode = NULL;
648 	INT count = 0;
649 	if (is_empty_list(list)) /* calls validate_list */
650 		return 0;
651 	ASSERT(func);
652 	lnode = lhead(list);
653 	while (lnode) {
654 		LNODE lnext = lnext(lnode);
655 		if ((*func)(param, lelement(lnode))) {
656 			detach_node_from_list(list, lnode);
657 			++count;
658 			if (ltype(list) == LISTDOFREE) {
659 				free_list_element(lelement(lnode));
660 			}
661 			if (!deleteall)
662 				return count;
663 		}
664 		lnode = lnext;
665 	}
666 	return count;
667 
668 }
669 /*==================================================
670  * trav_list_head - Return tail node of list
671  *  Only for internal use in FORLIST implementation
672  *================================================*/
673 LNODE
trav_list_head(LIST list)674 trav_list_head (LIST list)
675 {
676 	ASSERT(list);
677 	return list->l_head;
678 }
679 /*==================================================
680  * trav_list_tail - Return tail node of list
681  *  Only for internal use in FORLIST implementation
682  *================================================*/
683 LNODE
trav_list_tail(LIST list)684 trav_list_tail (LIST list)
685 {
686 	ASSERT(list);
687 	return list->l_tail;
688 }
689 /*=================================================
690  * list_destructor -- destructor for list
691  *  (destructor entry in vtable)
692  *===============================================*/
693 static void
list_destructor(VTABLE * obj)694 list_destructor (VTABLE *obj)
695 {
696 	LIST list = (LIST)obj;
697 	ASSERT((*obj) == &vtable_for_list);
698 	destroy_list(list);
699 }
700 /*=================================================
701  * listit_destructor -- destructor for list iterator
702  *  (vtable destructor)
703  *===============================================*/
704 static void
listit_destructor(VTABLE * obj)705 listit_destructor (VTABLE *obj)
706 {
707 	LIST_ITER listit = (LIST_ITER)obj;
708 	ASSERT(listit->vtable == &vtable_for_listit);
709 	free_list_iter(listit);
710 }
711 
712 /*=================================================
713  * addref_list -- increment reference count of list
714  *===============================================*/
715 void
addref_list(LIST list)716 addref_list (LIST list)
717 {
718 	ASSERT(list->vtable == &vtable_for_list);
719 	++list->l_refcnt;
720 }
721 /*=================================================
722  * release_list -- decrement reference count of list
723  *  and free if appropriate (ref count hits zero)
724  *===============================================*/
725 void
release_list(LIST list)726 release_list (LIST list)
727 {
728 	ASSERT(list->vtable == &vtable_for_list);
729 	--list->l_refcnt;
730 	if (!list->l_refcnt) {
731 		destroy_list(list);
732 	}
733 }
734