2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
24 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
25 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
26 //%% (c) Copyright 1993, 1994 Novell, Inc.
27 //%% $XConsortium: tt_object_list.C /main/3 1995/10/23 10:42:37 rswiston $
28 /* @(#)tt_object_list.C 1.17 93/07/30
32 * Copyright (c) 1991, 1992, 1993 by Sun Microsystems, Inc.
34 * This is the list package.
37 #include "util/tt_object_list.h"
38 #include "util/tt_assert.h"
39 #include "util/tt_iostream.h"
42 * Construct a new empty list.
53 * Copy a list. Sort of expensive, since elements aren't refcounted.
54 * Should be used sparingly.
57 _Tt_object_list(const _Tt_object_list &t)
59 _Tt_object_list_element *p, *n;
65 n = new _Tt_object_list_element;
82 * Destroy list, freeing all the elements.
87 _Tt_object_list_element *p, *q;
97 * Freeing all the elements, and reset.
99 void _Tt_object_list::
102 _Tt_object_list_element *p, *q;
115 * push: put a new element on the top of the list.
117 _Tt_object_list& _Tt_object_list::
118 push(const _Tt_object_ptr &e)
120 _Tt_object_list_element *n = new _Tt_object_list_element;
124 n->next = first; /* n->prev is nulled in constructor */
134 * pop: remove the element from the top of the list.
136 _Tt_object_list& _Tt_object_list::
139 _Tt_object_list_element *n;
141 ASSERT(first,"Pop of empty list");
155 * append: put a new element at the bottom of the list
157 _Tt_object_list& _Tt_object_list::
158 append(const _Tt_object_ptr &e)
160 _Tt_object_list_element *n = new _Tt_object_list_element;
164 n->prev = last; /* n->next is nulled in constructor */
174 * Create a new list which is the current list appended to the given list.
176 _Tt_object_list& _Tt_object_list::
177 append(_Tt_object_list_ptr l)
179 _Tt_object_list_ptr nl = new _Tt_object_list(*l);
180 append_destructive(nl);
185 * append_destructive: append all elements of supplied list to the list.
186 * as a side effect, empty the supplied list! This somewhat-surprising
187 * side effect lets us do the append very cheaply by reusing all the
188 * _Tt_object_list_element instances.
190 _Tt_object_list& _Tt_object_list::
191 append_destructive(_Tt_object_list_ptr l)
194 /* second list is empty, append does nothing */
196 } else if (0==first) {
197 /* first list is null */
202 /* real work to do */
203 l->first->prev = last;
204 last->next = l->first;
208 /* empty the second list */
215 * dequeue: remove the element from the bottom of the list.
217 _Tt_object_list& _Tt_object_list::
220 _Tt_object_list_element *n;
222 ASSERT(last,"Dequeue from empty list");
237 * Return a pointer to the contents of the element on the top of the list
239 _Tt_object_ptr &_Tt_object_list::
242 ASSERT(first,"top of empty list");
247 * Return a pointer to the contents of the element on the bottom of the list
249 _Tt_object_ptr &_Tt_object_list::
252 ASSERT(last,"bottom of empty list");
257 * Return a pointer to the contents of the n-th element on the list
259 * Note: this implementation could be very slow for large lists.
260 * The API routines use it heavily. It's likely the API accesses would be
261 * sequential, so an improvment would be to have a "cache pointer" to the
262 * last retrieved element along with its index; then sequential accesses
263 * could be very fast.
265 _Tt_object_ptr &_Tt_object_list::
266 operator[](int n) const
268 ASSERT(0<=n && n<=count(),"subscript out of range");
269 _Tt_object_list_element *p;
271 while(n--) p = p->next;
276 * Predicate that returns 1 iff list is empty, else returns 0
278 int _Tt_object_list::
285 * return number of elements in the list
288 * int _Tt_object_list::
295 * XDR encoding and decoding function for lists
297 bool_t _Tt_object_list::
298 xdr(XDR *xdrs, _Tt_new_xdrfn xdrfn, _Tt_object *(*make_new)())
300 if (! xdr_int(xdrs, &_count)) {
303 if (xdrs->x_op == XDR_ENCODE) {
304 _Tt_object_list_cursor cursor(this);
307 while (cursor.next()) {
309 if (optr.is_null()) {
312 if (! (*xdrfn)(xdrs, optr.c_pointer())) {
323 for (i=len; i > 0; --i) {
325 if (! (*xdrfn)(xdrs, ptr.c_pointer())) {
337 void _Tt_object_list::
338 print(_Tt_object_printfn print_elt, const _Tt_ostream &os) const
340 _Tt_object_list_element *cur;
343 (*print_elt)(os, (cur->data).c_pointer());
349 // verify that an object list is OK. Since lists are so generic, about all
350 // we can do is ensure that back pointers do point back, and that every
351 // element points to a object with a reasonable refcount. Here "reasonable"
352 // is greater than zero (a must) and less than 1,000,000 (an arbitrarily
353 // chosen upper bound.) We also allow the user to pass in a pointer to a
354 // predicate function which can verify the objects on the list. We call
355 // that with each object in turn. if it returns zero (false) there is a bad
356 // object on the list.
357 int _Tt_object_list::
358 verify(int (*verifier)(const _Tt_object *))
360 _Tt_object_list_element *cur;
364 if (0==cur->prev && cur!=first) {
366 "_Tt_object_list::verify: "
367 "bad null prev at element %d\n",
371 if (0!=cur->next && cur->next->prev!=cur) {
373 "_Tt_object_list::verify: "
374 "bad next->prev at element %d\n",
378 if (0==cur->next && cur!=last) {
380 "_Tt_object_list::verify: "
381 "bad null next at element %d\n",
385 if (cur->data.is_null()) {
387 "_Tt_object_list::verify: "
388 "null data pointer at element %d\n",
392 if (cur->data->verify_refcount(1000000) < 0) {
394 "_Tt_object_list::verify: "
395 "nonpositive _refcount_ at element %d\n",
399 if (cur->data->verify_refcount(1000000) > 0) {
401 "_Tt_object_list::verify: "
402 "absurdly large _refcount_ at element %d\n",
407 0 == (*verifier)(cur->data.c_pointer())) {
409 "_Tt_object_list::verify: "
410 "verifier rejected object at element %d\n",
425 * Constructor for list elements
427 _Tt_object_list_element::
428 _Tt_object_list_element()
434 _Tt_object_list_element::
435 ~_Tt_object_list_element()
440 * The _Tt_object_list_cursor methods implement an iterator which
441 * provides for convenient stepping along the list.
444 * The simple constructor for a cursor creates a cursor which
445 * points nowhere. reset(_Tt_object_list_ptr l) must be done before doing
446 * anything else with the cursor.
448 _Tt_object_list_cursor::
449 _Tt_object_list_cursor()
456 * The copy constructor for a cursor replicates the current position.
457 * Note that if two cursors point to the same element and one deletes
458 * it, the other cursor is hosed.
460 _Tt_object_list_cursor::
461 _Tt_object_list_cursor(const _Tt_object_list_cursor &c)
469 * The usual constructor for a cursor supplies a list. The cursor
470 * is set before the first element in the list (as if reset(list) had
473 _Tt_object_list_cursor::
474 _Tt_object_list_cursor(const _Tt_object_list_ptr &l)
479 flags &= ~(1<<DELETED);
482 _Tt_object_list_cursor::
483 ~_Tt_object_list_cursor()
488 * reset() moves a cursor back before the start of its list.
490 _Tt_object_list_cursor& _Tt_object_list_cursor::
493 ASSERT(flags&(1<<INIT),"Attempt to reset an unset cursor.");
495 flags &= ~(1<<DELETED);
500 * reset(_Tt_object_list_ptr l) resets the cursor to a new list, positioned
501 * before the first element.
503 _Tt_object_list_cursor& _Tt_object_list_cursor::
504 reset(const _Tt_object_list_ptr &l)
507 listhdr = _Tt_object_list_ptr(l);
513 * operator * returns a ref_counted pointer to the object under the cursor.
515 _Tt_object_ptr &_Tt_object_list_cursor::
519 return current->data;
521 return _Tt_object::null_ptr();
526 * operator -> returns a ref-counted pointer to the object under the cursor,
527 * which c++ will then apply the _Tt_object_PTR::operator-> to.
529 _Tt_object_ptr &_Tt_object_list_cursor::
532 return current->data;
536 * next() moves the cursor to the next element in the list and returns 1
537 * unless there is no next element, in which case it returns 0.
539 int _Tt_object_list_cursor::
542 flags &= ~(1<<DELETED);
544 current = current->next;
546 if (listhdr.is_null()) {
549 current = listhdr->first;
556 * prev() moves the cursor to the prev element in the list and returns 1
557 * unless there is no prev element, in which case it returns 0.
559 int _Tt_object_list_cursor::
562 if (flags&(1<<DELETED)) {
563 /* already on prev element */
564 flags &= ~(1<<DELETED);
565 } else if (current!=0) {
566 current = current->prev;
568 current = listhdr->last;
574 * insert(_Tt_object_ptr p) inserts a new element after the current one.
575 * inserting right after a delete puts the new element where the
576 * old deleted one was. inserting into a reset cursor puts the
577 * new element first. The cursor points to the new element after insert.
579 _Tt_object_list_cursor& _Tt_object_list_cursor::
580 insert(const _Tt_object_ptr &p)
582 flags &= ~(1<<DELETED);
583 if (current == 0) { /* reset cursor */
585 current = listhdr->first;
587 _Tt_object_list_element *n = new _Tt_object_list_element;
589 if (current->next != 0)
590 current->next->prev = n;
593 n->next = current->next;
595 n->data = _Tt_object_ptr(p);
603 * remove() deletes the element under the cursor. The cursor is set up
604 * so that next() after remove() will get the element after the one
605 * that was removed, and prev() after remove() will get the element before
606 * the one that was removed.
608 _Tt_object_list_cursor& _Tt_object_list_cursor::
611 ASSERT(current,"No current element to delete");
612 register _Tt_object_list_element *p = current;
615 p->next->prev = p->prev;
617 listhdr->last = p->prev;
619 p->prev->next = p->next;
621 listhdr->first = p->next;
628 * is_valid returns 1 if there is an element under the cursor, else 0
630 int _Tt_object_list_cursor::
636 implement_ptr_to(_Tt_object)
637 implement_ptr_to(_Tt_object_list)