wvdbusserver: implement NameHasOwner request.
[wvstreams.git] / include / wvlinklist.h
bloba7b3337604b38ee2429afde5a5e82aa5ee1f5ece
1 /* -*- Mode: C++ -*-
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * A linked list container.
6 */
7 #ifndef __WVLINKLIST_H
8 #define __WVLINKLIST_H
10 #include "wvtypetraits.h"
11 #include "wvsorter.h"
13 /**
14 * @internal
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>.
21 class WvListBase
23 WvListBase(const WvListBase &l); // copy constructor - not actually defined anywhere!
24 private:
25 //This is private to force people to pass by reference, not by value
26 WvListBase& operator= (const WvListBase &l);
28 public:
29 WvLink head, *tail;
31 /** Creates an empty linked list. */
32 WvListBase() : head(NULL, false)
33 { tail = &head; }
35 /**
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
43 size_t count() const;
45 /**
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
53 void reverse();
55 /**
56 * Quickly determines if the list is empty.
58 * This is much faster than checking count() == 0.
60 * Returns: true if empty
62 bool isempty() const
63 { return head.next == NULL; }
65 /**
66 * @internal
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>.
73 class IterBase
75 public:
76 const WvListBase *list;
77 WvLink *link, *prev;
79 /**
80 * Binds the iterator to the specified list.
81 * "l" is the list
83 IterBase(const WvListBase &l)
84 { list = &l; link = NULL; }
86 /**
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; }
94 /**
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
103 WvLink *next()
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
111 WvLink *cur() const
112 { return link; }
115 * Returns a void pointer to the object at the iterator's current
116 * location. You should almost never need this. Use ptr() instead.
118 void *vptr() const
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
132 * was found
134 WvLink *find(const void *data);
137 * Repositions the iterator over the element that matches the
138 * specified value.
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
144 * was found
146 WvLink *find_next(const void*data);
152 * A linked list container class.
154 * Some rather horrible macros are used to declare actual concrete
155 * list types.
157 * Example:
159 * DeclareWvList(WvString);
161 * int main()
163 * WvStringList l;
164 * WvStringList::Iter i(l);
166 * ... fill the list ...
168 * i.rewind();
169 * while (i.next())
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
176 * set to true.
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
184 * lists.
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
196 template<class T>
197 class WvList : public WvListBase
199 // copy constructor: not defined anywhere!
200 WvList(const WvList &list);
202 public:
203 /** Creates an empty linked list. */
204 WvList()
208 * Destroys the linked list.
210 * Destroys any elements that were added with autofree == true.
213 ~WvList()
214 { zap(); }
216 /** Invoked by subclasses after the linked list is first created. */
217 void setup() {}
219 /** Invoked by subclasses before the linked list is destroyed. */
220 void shutdown() {}
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)
230 while (head.next)
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
241 T *first() const
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
251 T *last() const
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
303 void unlink(T *data)
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.
312 void unlink_first()
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
321 * destroy == true.
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;
328 if(next != NULL)
330 T *obj = (destroy && next->get_autofree()) ?
331 static_cast<T*>(next->data) : NULL;
332 if (next == tail) tail = after;
333 next->unlink(after);
334 if (obj)
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
352 public:
354 * Binds the iterator to the specified list.
355 * "l" is the list
357 Iter(const WvList &l) : IterBase(l)
361 * Returns a pointer to the current element.
362 * Returns: the element pointer, possibly null
364 T *ptr() const
365 { return (T *)link->data; }
367 WvIterStuff(T);
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);
393 link = prev->next;
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
400 * next element.
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);
412 link = prev;
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