2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * A linked list container.
10 #include "wvtypetraits.h"
15 * The untyped base class of WvList<T>.
17 * Putting common code in here allows us to prevent it from being
18 * replicated by each template instantiation of WvList<T>.
23 WvListBase(const WvListBase
&l
); // copy constructor - not actually defined anywhere!
25 //This is private to force people to pass by reference, not by value
26 WvListBase
& operator= (const WvListBase
&l
);
31 /** Creates an empty linked list. */
32 WvListBase() : head(NULL
, false)
36 * Returns the number of elements in the list.
38 * This function causes a full traversal of the list which may be
39 * overly inefficient depending on how and when it is used.
41 * Returns: the number of elements
46 * Reverses the order of elements in the list.
48 * This function traverses the list and rearranges the pointers
49 * and updates the pointers to head & tail appropriately.
51 * It does nothing for lists of count<2
56 * Quickly determines if the list is empty.
58 * This is much faster than checking count() == 0.
60 * Returns: true if empty
63 { return head
.next
== NULL
; }
67 * The untyped base class of WvList<T>::Iter.
69 * Putting common code in here allows us to prevent it from being
70 * replicated by each template instantiation of WvList<T>.
76 const WvListBase
*list
;
80 * Binds the iterator to the specified list.
83 IterBase(const WvListBase
&l
)
84 { list
= &l
; link
= NULL
; }
87 * Rewinds the iterator to make it point to an imaginary element
88 * preceeding the first element of the list.
90 void rewind() // dropping a const pointer here! Danger!
91 { prev
= NULL
; link
= &((WvListBase
*)list
)->head
; }
95 * Moves the iterator along the list to point to the next element.
97 * If the iterator had just been rewound, it now points to the
98 * first element of the list.
100 * Returns: the current WvLink pointer, or null if there were no
101 * more elements remaining in the traversal sequence
104 { prev
= link
; return link
= link
->next
; }
107 * Returns a pointer to the WvLink at the iterator's current location.
108 * Returns: the current WvLink pointer, or null if there were no
109 * more elements remaining in the traversal sequence
115 * Returns a void pointer to the object at the iterator's current
116 * location. You should almost never need this. Use ptr() instead.
119 { return link
->data
; }
122 * Rewinds the iterator and repositions it over the element that
123 * matches the specified value.
125 * Uses pointer equality (object identity) as the criteria for
126 * finding the matching element.
128 * In order to locate multiple matching elements, first call find()
129 * and then use find_next().
131 * Returns: the current WvLink pointer, or null if no such element
134 WvLink
*find(const void *data
);
137 * Repositions the iterator over the element that matches the
140 * Uses pointer equality (object identity) as the criteria for
141 * finding the matching element.
143 * Returns: the current WvLink pointer, or null if no such element
146 WvLink
*find_next(const void*data
);
152 * A linked list container class.
154 * Some rather horrible macros are used to declare actual concrete
159 * DeclareWvList(WvString);
164 * WvStringList::Iter i(l);
166 * ... fill the list ...
170 * printf("%s\\n", i.str);
174 * Deallocating list will free all of the WvLinks in the list, but
175 * will only free the user objects that were added with autofree
178 * We need to malloc memory for each WvLink as well as the data it
179 * stores; this is unnecessarily slow. I would rather have made a
180 * base "Link" class for object types that could be stored as links
181 * in a list, and then used object->next instead of all the
182 * List Iterator stuff, but the end result was pure ugliness, so I
183 * gave up. At least this way, the same object can be in multiple
186 * List type construction is facilitated by the following macros:
188 * - DeclareWvList(Type): creates a subclass named TypeList
189 * that contains pointers to Type.
190 * - DeclareWvList2(name, Type): as the above, but calls the
191 * resulting class by the specified name.
194 * "T" is the object type
197 class WvList
: public WvListBase
199 // copy constructor: not defined anywhere!
200 WvList(const WvList
&list
);
203 /** Creates an empty linked list. */
208 * Destroys the linked list.
210 * Destroys any elements that were added with autofree == true.
216 /** Invoked by subclasses after the linked list is first created. */
219 /** Invoked by subclasses before the linked list is destroyed. */
223 * Clears the linked list.
225 * If destroy is true, destroys any elements that were added with autofree == true.
228 void zap(bool destroy
= true)
231 unlink_after(& head
, destroy
);
235 * Returns a pointer to the first element in the linked list.
237 * The list must be non-empty.
239 * Returns: the element pointer, possibly null
242 { return (T
*)head
.next
->data
; }
245 * Returns a pointer to the last element in the linked list.
247 * The list must be non-empty.
249 * Returns: the element pointer, possibly null
252 { return (T
*)tail
->data
; }
255 * Adds the element after the specified link in the list.
257 * "link" is the link preceeding the desired location of the element
258 * to be inserted, non-null
259 * "data" is the element pointer, may be null
260 * "autofree" is if true, takes ownership of the element
261 * "id" is an optional string to associate with the element, or null
263 void add_after(WvLink
*after
, T
*data
, bool autofree
,
264 const char *id
= NULL
)
266 (void)new WvLink((void *)data
, after
, tail
, autofree
, id
);
270 * Appends the element to the end of the list.
272 * "data" is the element pointer, may be null
273 * "autofree" is if true, takes ownership of the element
274 * "id" is an optional string to associate with the element, or null
276 void append(T
*data
, bool autofree
, const char *id
= NULL
)
277 { add_after(tail
, data
, autofree
, id
); }
280 * Synonym for append(T*, bool, char*).
281 * @see append(T*, bool, char*)
283 void add(T
*data
, bool autofree
, const char *id
= NULL
)
284 { append(data
, autofree
, id
); }
287 * Prepends the element to the beginning of the list.
289 * "data" is the element pointer, may be null
290 * "autofree" is if true, takes ownership of the element
291 * "id" is an optional string to associate with the element, or null
293 void prepend(T
*data
, bool autofree
, const char *id
= NULL
)
294 { add_after(&head
, data
, autofree
, id
); }
297 * Unlinks the specified element from the list.
299 * Destroys the element if it was added with autofree == true.
301 * "data" is the element pointer, may be null
304 { Iter
i(*this); while (i
.find(data
)) i
.unlink(); }
307 * Unlinks the first element from the list.
309 * Destroys the element if it was added with autofree == true.
314 if(head
.next
!= NULL
)
315 { Iter
i(*this); i
.rewind(); i
.next(); i
.unlink(); }
318 * Unlinks the element that follows the specified link in the list.
320 * Destroys the element if it was added with autofree == true and
323 * "after" is the link preceeding the element to be removed, non-null
325 void unlink_after(WvLink
*after
, bool destroy
= true)
327 WvLink
*next
= after
->next
;
330 T
*obj
= (destroy
&& next
->get_autofree()) ?
331 static_cast<T
*>(next
->data
) : NULL
;
332 if (next
== tail
) tail
= after
;
335 WvTraits
<T
>::release(obj
);
340 * The iterator type for linked lists.
342 * An iterator instance does not initially point to any valid
343 * elements in a list. Before using, it must be reset using rewind()
344 * which causes it to point to an imaginary element located before
345 * the first elements in the list. Then next() must be invoked
346 * to incrementally move the iterator along the list to first element,
347 * and then later to the second, third, and subsequent elements.
350 class Iter
: public WvListBase::IterBase
354 * Binds the iterator to the specified list.
357 Iter(const WvList
&l
) : IterBase(l
)
361 * Returns a pointer to the current element.
362 * Returns: the element pointer, possibly null
365 { return (T
*)link
->data
; }
370 * Returns the state of autofree for the current element.
372 bool get_autofree() const
374 return link
->get_autofree();
378 * Sets the state of autofree for the current element.
380 void set_autofree(bool autofree
)
382 link
->set_autofree(autofree
);
386 * Unlinks the current element from the list and automatically
387 * increments the iterator to point to the next element as if
388 * next() had been called.
390 void unlink(bool destroy
= true)
392 if (prev
) ((WvList
*)list
)->unlink_after(prev
, destroy
);
397 * Unlinks the current element from the list but unlike unlink()
398 * automatically returns the iterator to the previous link in
399 * the list such that next() must be called to obtain the
402 * This version allows for writing neater loop structures since
403 * an element can be unlinked in mid-traversal while still allowing
404 * the iterator to be incremented at the top of the loop as usual.
406 * Calling xunlink() twice in a row is currently unsupported.
409 void xunlink(bool destroy
= true)
411 if (prev
) ((WvList
*)list
)->unlink_after(prev
, destroy
);
416 /** The sorted iterator type for linked lists. */
417 typedef class WvSorter
<T
, WvListBase
, WvListBase::IterBase
> Sorter
;
420 #define DeclareWvList2(_classname_, _type_) \
421 typedef class WvList<_type_> _classname_
423 #define DeclareWvList(_type_) DeclareWvList2(_type_##List, _type_)
426 #endif // __WVLINKLIST_H