1 |
|
---|
2 | /*
|
---|
3 | *@@sourcefile bs_list.h:
|
---|
4 | * replacement for the STL list class template.
|
---|
5 | * All STL code has been removed from WarpIN
|
---|
6 | * with 0.9.14.
|
---|
7 | *
|
---|
8 | * This list class only supplies a subset of the
|
---|
9 | * STL list functionality. The advantages of using
|
---|
10 | * this new implementation though are the following:
|
---|
11 | *
|
---|
12 | * 1) This list template produces FAR less code
|
---|
13 | * bloat. Most code here is inlined and only
|
---|
14 | * consists of a couple of lines for every
|
---|
15 | * method, which mostly calls into the
|
---|
16 | * linklist.c code from the XWPhelpers. In
|
---|
17 | * other words, the list class template is
|
---|
18 | * only a wrapper around linklist.c for
|
---|
19 | * type-safety.
|
---|
20 | *
|
---|
21 | * 2) WarpIN compiles almost twice as fast now
|
---|
22 | * because the incredibly complex STL headers
|
---|
23 | * with all those nested templates are gone.
|
---|
24 | *
|
---|
25 | * 3) This implementation does not call copy
|
---|
26 | * constructors all the time. The STL is not
|
---|
27 | * good at managing pointers; instead, its
|
---|
28 | * containers assume to contain the real
|
---|
29 | * data at all times.
|
---|
30 | *
|
---|
31 | * By contrast, the list code here _only_
|
---|
32 | * operates on pointers. With list<P>, it
|
---|
33 | * is assumed that P is a type that was
|
---|
34 | * created with new and that delete can
|
---|
35 | * (and will) be invoked on it.
|
---|
36 | * You cannot instantiate the list class for
|
---|
37 | * a non-pointer type.
|
---|
38 | *
|
---|
39 | * The XWPHelpers linklist.c code has been used
|
---|
40 | * in XWorkplace forever and can be considered
|
---|
41 | * fairly bug-free.
|
---|
42 | *
|
---|
43 | * This header supplies two class templates:
|
---|
44 | *
|
---|
45 | * 1) list_iterator<P> is a type-safe wrapper
|
---|
46 | * around the LISTNODE. list_iterator++
|
---|
47 | * will give you the next node, for example,
|
---|
48 | * and *list_iterator gives you the actual
|
---|
49 | * data. This is very similar to the STL.
|
---|
50 | *
|
---|
51 | * 2) list<P> is a type-safe wrapper around
|
---|
52 | * LINKLIST. It typedefs an iterator
|
---|
53 | * internally so you can use list<P>::iterator
|
---|
54 | * as with the STL. Again, this will only
|
---|
55 | * handle _pointer_ types.
|
---|
56 | *
|
---|
57 | * Terminology:
|
---|
58 | *
|
---|
59 | * -- list<P>: the list itself. A template wrapper
|
---|
60 | * around a LINKLIST.
|
---|
61 | *
|
---|
62 | * -- list node: a node inside a list<P>, uses
|
---|
63 | * a LISTNODE inside.
|
---|
64 | *
|
---|
65 | * -- list<P>::iterator: a template wrapper around
|
---|
66 | * a LISTNODE. *(list<P>::iterator) points
|
---|
67 | * to the data.
|
---|
68 | *
|
---|
69 | * -- data: a pointer of type P that is stored with
|
---|
70 | * the list node.
|
---|
71 | *
|
---|
72 | * One more difference to the STL is that the
|
---|
73 | * list operates in two modes. When constructing
|
---|
74 | * a list<P>, the constructor expects the
|
---|
75 | * mode to be specified, which must be one
|
---|
76 | * of the following:
|
---|
77 | *
|
---|
78 | * -- STORE: whenever a node is deleted,
|
---|
79 | * the list should invoke delete on
|
---|
80 | * the data (P pointer) also.
|
---|
81 | *
|
---|
82 | * -- SHADOW: delete must not be invoked.
|
---|
83 | *
|
---|
84 | * Presently, the list constructor enforces the
|
---|
85 | * mode to be specified to make sure that the
|
---|
86 | * implementor makes a decision about which list
|
---|
87 | * mode should be used. This might change in
|
---|
88 | * the future.
|
---|
89 | *
|
---|
90 | * Example usage:
|
---|
91 | *
|
---|
92 | + struct MYSTRUCT
|
---|
93 | + {
|
---|
94 | + int dummy;
|
---|
95 | +
|
---|
96 | + MYSTRUCT(i) {dummy = i;}
|
---|
97 | + }
|
---|
98 | +
|
---|
99 | + // create a list of MYSTRUCT pointers
|
---|
100 | + list<MYSTRUCT*> MyList(STORE);
|
---|
101 | + // store new MYSTRUCT's in the list
|
---|
102 | + MyList.push_back(new MYSTRUCT(1));
|
---|
103 | + MyList.push_back(new MYSTRUCT(2));
|
---|
104 | +
|
---|
105 | + // now run through the list
|
---|
106 | + list<MYSTRUCT*>::iterator start, end;
|
---|
107 | + start = MyList.begin(); // returns first list node
|
---|
108 | + end = MyList.end(); // returns past last list node
|
---|
109 | + while (start != end) // for all items
|
---|
110 | + {
|
---|
111 | + MYSTRUCT *pData = *start; // dereference the data
|
---|
112 | + if (pData->dummy == 2)
|
---|
113 | + break;
|
---|
114 | +
|
---|
115 | + // next list node
|
---|
116 | + start++
|
---|
117 | + }
|
---|
118 | *
|
---|
119 | *@@added V0.9.14 (2001-07-12) [umoeller]
|
---|
120 | *@@include #include "helpers\linklist.h"
|
---|
121 | */
|
---|
122 |
|
---|
123 | #ifndef BSLIST_INCLUDED
|
---|
124 | #define BSLIST_INCLUDED
|
---|
125 |
|
---|
126 | /* ******************************************************************
|
---|
127 | *
|
---|
128 | * Replacement list class template
|
---|
129 | *
|
---|
130 | ********************************************************************/
|
---|
131 |
|
---|
132 | #include "helpers\linklist.h"
|
---|
133 |
|
---|
134 | template <class P>
|
---|
135 | class list;
|
---|
136 |
|
---|
137 | /*
|
---|
138 | *@@ list_iterator:
|
---|
139 | * a list_iterator<P> is a LISTNODE
|
---|
140 | * whose pNode->pItemData == P.
|
---|
141 | *
|
---|
142 | * list<P> typedefs list<P>::iterator
|
---|
143 | * to be a list_iterator<P>.
|
---|
144 | *
|
---|
145 | * P must be deletable (i.e. created
|
---|
146 | * on the heap with new()).
|
---|
147 | */
|
---|
148 |
|
---|
149 | template <class P>
|
---|
150 | class list_iterator
|
---|
151 | {
|
---|
152 | /*
|
---|
153 | public:
|
---|
154 | void* operator new(size_t n) { return malloc(n);};
|
---|
155 | void operator delete(void* p) { free(p);};
|
---|
156 | */
|
---|
157 |
|
---|
158 | public:
|
---|
159 | PLISTNODE pNode;
|
---|
160 |
|
---|
161 | /*
|
---|
162 | *@@ list_iterator:
|
---|
163 | * constructor.
|
---|
164 | */
|
---|
165 |
|
---|
166 | inline list_iterator()
|
---|
167 | {
|
---|
168 | pNode = 0;
|
---|
169 | }
|
---|
170 |
|
---|
171 | /*
|
---|
172 | *@@ list_iterator:
|
---|
173 | * copy constructor to convert from a
|
---|
174 | * PLISTNODE.
|
---|
175 | */
|
---|
176 |
|
---|
177 | inline list_iterator(const PLISTNODE p)
|
---|
178 | {
|
---|
179 | pNode = p;
|
---|
180 | }
|
---|
181 |
|
---|
182 | /*
|
---|
183 | *@@ ~list_iterator:
|
---|
184 | * destructor. Does nothing.
|
---|
185 | */
|
---|
186 |
|
---|
187 | inline ~list_iterator()
|
---|
188 | {
|
---|
189 |
|
---|
190 | }
|
---|
191 |
|
---|
192 | /*
|
---|
193 | *@@ operator++:
|
---|
194 | * overloaded prefix ++ operator so we
|
---|
195 | * can easily run thru the list nodes.
|
---|
196 | */
|
---|
197 |
|
---|
198 | void inline operator++()
|
---|
199 | {
|
---|
200 | if (pNode)
|
---|
201 | pNode = pNode->pNext;
|
---|
202 | }
|
---|
203 |
|
---|
204 | /*
|
---|
205 | *@@ operator++:
|
---|
206 | * overloaded postfix ++ operator so
|
---|
207 | * we can easily run thru the list nodes.
|
---|
208 | *
|
---|
209 | * The int i is just stupid C++ syntax, the
|
---|
210 | * int is always zero, it's just for
|
---|
211 | * distinguishing between prefix and postfix.
|
---|
212 | */
|
---|
213 |
|
---|
214 | void inline operator++(int i)
|
---|
215 | {
|
---|
216 | if (pNode)
|
---|
217 | pNode = pNode->pNext;
|
---|
218 | }
|
---|
219 | };
|
---|
220 |
|
---|
221 | template <class P>
|
---|
222 | bool inline operator==(list_iterator<P> &p1, list_iterator<P> &p2)
|
---|
223 | {
|
---|
224 | return (p1.pNode == p2.pNode);
|
---|
225 | }
|
---|
226 |
|
---|
227 | template <class P>
|
---|
228 | bool inline operator==(const list_iterator<P> &p1, const list_iterator<P> &p2)
|
---|
229 | {
|
---|
230 | return (p1.pNode == p2.pNode);
|
---|
231 | }
|
---|
232 |
|
---|
233 | template <class P>
|
---|
234 | bool inline operator!=(list_iterator<P> &p1, list_iterator<P> &p2)
|
---|
235 | {
|
---|
236 | return (p1.pNode != p2.pNode);
|
---|
237 | }
|
---|
238 |
|
---|
239 | template <class P>
|
---|
240 | P inline operator*(list_iterator<P> &p)
|
---|
241 | {
|
---|
242 | return (P)p.pNode->pItemData;
|
---|
243 | }
|
---|
244 |
|
---|
245 | /*
|
---|
246 | *@@ list_reverse_iterator:
|
---|
247 | *
|
---|
248 | */
|
---|
249 |
|
---|
250 | template <class T>
|
---|
251 | class list_reverse_iterator : public list_iterator<T>
|
---|
252 | {
|
---|
253 | public:
|
---|
254 | inline list_reverse_iterator()
|
---|
255 | : list_iterator<T>()
|
---|
256 | {
|
---|
257 | }
|
---|
258 |
|
---|
259 | inline list_reverse_iterator(const PLISTNODE p)
|
---|
260 | : list_iterator<T>(p)
|
---|
261 | {
|
---|
262 | }
|
---|
263 |
|
---|
264 | void inline operator++()
|
---|
265 | {
|
---|
266 | if (pNode)
|
---|
267 | pNode = pNode->pPrevious;
|
---|
268 | }
|
---|
269 |
|
---|
270 | // overload postfix ++ operator: first arg is class, second is int
|
---|
271 | // (stupid compiler syntax, the int is always zero, it's just
|
---|
272 | // for distinguishing between prefix and postfix)
|
---|
273 | void inline operator++(int i)
|
---|
274 | {
|
---|
275 | if (pNode)
|
---|
276 | pNode = pNode->pPrevious;
|
---|
277 | }
|
---|
278 | };
|
---|
279 |
|
---|
280 | enum LISTMODE {SHADOW, STORE};
|
---|
281 |
|
---|
282 | /*
|
---|
283 | *@@ list:
|
---|
284 | * a list<P> is a list whose LISTNODES
|
---|
285 | * point to instances of P.
|
---|
286 | *
|
---|
287 | * As opposed to the STL list, this does
|
---|
288 | * not store copies of the data. Instead,
|
---|
289 | * it is assumed that P is deletable. It
|
---|
290 | * must be a pointer and have been created
|
---|
291 | * with new().
|
---|
292 | *
|
---|
293 | * A list can operate in two modes. In
|
---|
294 | * "shadow" mode, the list will not invoke
|
---|
295 | * delete on the data pointers when the
|
---|
296 | * nodes are removed. In "store" mode,
|
---|
297 | * it will. It is not a good idea to have
|
---|
298 | * to "store" lists point to the same
|
---|
299 | * data members; in general, if you have
|
---|
300 | * several lists pointing to the same data,
|
---|
301 | * you should have one master list in
|
---|
302 | * "store" mode only.
|
---|
303 | */
|
---|
304 |
|
---|
305 | template <class P>
|
---|
306 | class list
|
---|
307 | {
|
---|
308 | /*
|
---|
309 | public:
|
---|
310 | void* operator new( size_t n) { return malloc(n);};
|
---|
311 | void operator delete( void* p) { free(p);};
|
---|
312 | */
|
---|
313 |
|
---|
314 | public:
|
---|
315 | const LISTMODE _mode;
|
---|
316 |
|
---|
317 | protected:
|
---|
318 | LINKLIST ll;
|
---|
319 |
|
---|
320 | void KillNode(PLISTNODE p)
|
---|
321 | {
|
---|
322 | P p2 = (P)p->pItemData;
|
---|
323 |
|
---|
324 | #ifdef __DEBUG__
|
---|
325 | BSRoot::WriteToDebugLog("list::KillNode for %s at 0x%lX\n",
|
---|
326 | p2->QueryClassName(),
|
---|
327 | p2);
|
---|
328 | #endif
|
---|
329 |
|
---|
330 | if (_mode == STORE)
|
---|
331 | delete p2;
|
---|
332 | lstRemoveNode(&ll, p);
|
---|
333 | }
|
---|
334 |
|
---|
335 | /*
|
---|
336 | *@@ CopyFrom:
|
---|
337 | * private helper for copy constructors and such.
|
---|
338 | */
|
---|
339 |
|
---|
340 | void CopyFrom(const list<P> &llSource)
|
---|
341 | {
|
---|
342 | PLISTNODE p = lstQueryFirstNode((PLINKLIST)&llSource.ll);
|
---|
343 | while (p)
|
---|
344 | {
|
---|
345 | lstAppendItem(&ll, p->pItemData);
|
---|
346 |
|
---|
347 | p = p->pNext;
|
---|
348 | }
|
---|
349 | }
|
---|
350 |
|
---|
351 | public:
|
---|
352 | typedef list_iterator<P> iterator;
|
---|
353 | typedef list_reverse_iterator<P> reverse_iterator;
|
---|
354 |
|
---|
355 | /*
|
---|
356 | *@@ list:
|
---|
357 | * default constructor.
|
---|
358 | */
|
---|
359 |
|
---|
360 | list(LISTMODE mode) // = SHADOW)
|
---|
361 | : _mode(mode)
|
---|
362 | {
|
---|
363 | lstInit(&ll, FALSE);
|
---|
364 | }
|
---|
365 |
|
---|
366 | // copy constructor
|
---|
367 | list(const list<P> &llSource)
|
---|
368 | : _mode(SHADOW)
|
---|
369 | {
|
---|
370 | CopyFrom(llSource);
|
---|
371 | }
|
---|
372 |
|
---|
373 | /*
|
---|
374 | *@@ ~list:
|
---|
375 | * destructor.
|
---|
376 | *
|
---|
377 | * If the list is in STORE mode,
|
---|
378 | * delete will be invoked on each
|
---|
379 | * list data item as well.
|
---|
380 | */
|
---|
381 |
|
---|
382 | ~list()
|
---|
383 | {
|
---|
384 | clear();
|
---|
385 | }
|
---|
386 |
|
---|
387 | /*
|
---|
388 | *@@ operator=:
|
---|
389 | * copies the list nodes, but does NOT
|
---|
390 | * copy the data nodes.
|
---|
391 | */
|
---|
392 |
|
---|
393 | const list<P> operator=(const list<P> &llSource)
|
---|
394 | {
|
---|
395 | CopyFrom(llSource);
|
---|
396 | return *this;
|
---|
397 | }
|
---|
398 |
|
---|
399 | /*
|
---|
400 | *@@ push_front:
|
---|
401 | *
|
---|
402 | */
|
---|
403 |
|
---|
404 | void inline push_front(const P p)
|
---|
405 | {
|
---|
406 | lstInsertItemBefore(&ll,
|
---|
407 | p,
|
---|
408 | 0); // index to insert before
|
---|
409 | }
|
---|
410 |
|
---|
411 | /*
|
---|
412 | *@@ push_back:
|
---|
413 | *
|
---|
414 | */
|
---|
415 |
|
---|
416 | void inline push_back(const P p)
|
---|
417 | {
|
---|
418 | lstAppendItem(&ll, p);
|
---|
419 | }
|
---|
420 |
|
---|
421 | /*
|
---|
422 | *@@ remove:
|
---|
423 | * removes the list node which
|
---|
424 | * points to the specified data
|
---|
425 | * item.
|
---|
426 | *
|
---|
427 | * If the list is in STORE mode,
|
---|
428 | * delete will be invoked on p's
|
---|
429 | * data item as well.
|
---|
430 | */
|
---|
431 |
|
---|
432 | void inline remove(P p)
|
---|
433 | {
|
---|
434 | PLISTNODE pNode = lstNodeFromItem(&ll, p);
|
---|
435 | if (pNode)
|
---|
436 | KillNode(pNode);
|
---|
437 | }
|
---|
438 |
|
---|
439 | /*
|
---|
440 | *@@ pop_back:
|
---|
441 | * removes the last element.
|
---|
442 | *
|
---|
443 | * If the list is in STORE mode,
|
---|
444 | * delete will be invoked on the
|
---|
445 | * data item as well.
|
---|
446 | */
|
---|
447 |
|
---|
448 | void inline pop_back()
|
---|
449 | {
|
---|
450 | PLISTNODE pNode = lstQueryLastNode(&ll);
|
---|
451 | if (pNode)
|
---|
452 | KillNode(pNode);
|
---|
453 | }
|
---|
454 |
|
---|
455 | /*
|
---|
456 | *@@ erase:
|
---|
457 | * erases the specified list node.
|
---|
458 | * Returns the node after that node
|
---|
459 | * or end().
|
---|
460 | *
|
---|
461 | * If the list is in STORE mode,
|
---|
462 | * delete will be invoked on the
|
---|
463 | * data item as well.
|
---|
464 | */
|
---|
465 |
|
---|
466 | void inline erase(iterator pos)
|
---|
467 | {
|
---|
468 | KillNode(pos.pNode);
|
---|
469 | }
|
---|
470 |
|
---|
471 | /*
|
---|
472 | *@@ erase:
|
---|
473 | *
|
---|
474 | * If the list is in STORE mode,
|
---|
475 | * delete will be invoked on each
|
---|
476 | * list data item as well.
|
---|
477 | */
|
---|
478 |
|
---|
479 | void inline erase(iterator first, // first to erase
|
---|
480 | iterator last) // last to erase (not included)
|
---|
481 | {
|
---|
482 | PLISTNODE p = first.pNode;
|
---|
483 | while (p)
|
---|
484 | {
|
---|
485 | PLISTNODE pNext = p->pNext;
|
---|
486 |
|
---|
487 | KillNode(p);
|
---|
488 |
|
---|
489 | p = pNext;
|
---|
490 | if (p == last.pNode)
|
---|
491 | break;
|
---|
492 | }
|
---|
493 | }
|
---|
494 |
|
---|
495 | /*
|
---|
496 | *@@ clear:
|
---|
497 | * empties the entire list.
|
---|
498 | *
|
---|
499 | * If the list is in STORE mode,
|
---|
500 | * delete will be invoked on each
|
---|
501 | * list data item as well.
|
---|
502 | */
|
---|
503 |
|
---|
504 | void clear()
|
---|
505 | {
|
---|
506 | PLISTNODE p = lstQueryFirstNode(&ll);
|
---|
507 | while (p)
|
---|
508 | {
|
---|
509 | PLISTNODE pNext = p->pNext;
|
---|
510 |
|
---|
511 | KillNode(p);
|
---|
512 |
|
---|
513 | p = pNext;
|
---|
514 | }
|
---|
515 | }
|
---|
516 |
|
---|
517 | /*
|
---|
518 | *@@ empty:
|
---|
519 | * returns TRUE if the list is empty.
|
---|
520 | */
|
---|
521 |
|
---|
522 | bool inline empty() const
|
---|
523 | {
|
---|
524 | return (lstCountItems(&ll) == 0);
|
---|
525 | }
|
---|
526 |
|
---|
527 | /*
|
---|
528 | *@@ count:
|
---|
529 | * returns the no.of items on the list.
|
---|
530 | *
|
---|
531 | *@@added V0.9.18 (2002-03-08) [umoeller]
|
---|
532 | */
|
---|
533 |
|
---|
534 | unsigned long inline count() const
|
---|
535 | {
|
---|
536 | return (lstCountItems(&ll));
|
---|
537 | }
|
---|
538 |
|
---|
539 | /*
|
---|
540 | *@@ begin:
|
---|
541 | * returns a list iterator to the first
|
---|
542 | * list item.
|
---|
543 | */
|
---|
544 |
|
---|
545 | list<P>::iterator inline begin() const
|
---|
546 | {
|
---|
547 | return lstQueryFirstNode(&ll);
|
---|
548 | }
|
---|
549 |
|
---|
550 | /*
|
---|
551 | *@@ end:
|
---|
552 | * returns a list iterator to point
|
---|
553 | * behind the last list item.
|
---|
554 | *
|
---|
555 | * This is special. STL list defines
|
---|
556 | * the "end" iterator to point _past_
|
---|
557 | * the last element... it does not
|
---|
558 | * return the last element itself.
|
---|
559 | *
|
---|
560 | * A regular STL item loop looks like
|
---|
561 | * this:
|
---|
562 | *
|
---|
563 | + list<X>::iterator i;
|
---|
564 | + for (i = list.begin();
|
---|
565 | + i != list.end();
|
---|
566 | + i++)
|
---|
567 | + {
|
---|
568 | + X x = *i;
|
---|
569 | + }
|
---|
570 | *
|
---|
571 | * So for convenience, we define end()
|
---|
572 | * to return NULL, because
|
---|
573 | * list_iterator::operator++ will set its
|
---|
574 | * member to NULL also if there's no next
|
---|
575 | * item.
|
---|
576 | */
|
---|
577 |
|
---|
578 | const list<P>::iterator inline end() const
|
---|
579 | {
|
---|
580 | return (const list<P>::iterator)NULL;
|
---|
581 | }
|
---|
582 |
|
---|
583 | /*
|
---|
584 | *@@ rbegin:
|
---|
585 | * for reverse iteration. Returns the last
|
---|
586 | * item.
|
---|
587 | */
|
---|
588 |
|
---|
589 | list<P>::reverse_iterator inline rbegin()
|
---|
590 | {
|
---|
591 | return lstQueryLastNode(&ll);
|
---|
592 | }
|
---|
593 |
|
---|
594 | list<P>::reverse_iterator inline rend()
|
---|
595 | {
|
---|
596 | return (list<P>::reverse_iterator)NULL;
|
---|
597 | }
|
---|
598 |
|
---|
599 | P inline back()
|
---|
600 | {
|
---|
601 | PLISTNODE pNode = lstQueryLastNode(&ll);
|
---|
602 | if (pNode)
|
---|
603 | return (P)pNode->pItemData;
|
---|
604 |
|
---|
605 | return (P)NULL;
|
---|
606 | }
|
---|
607 |
|
---|
608 | void inline sort(PFNSORTLIST pfnCompare)
|
---|
609 | {
|
---|
610 | lstQuickSort(&ll,
|
---|
611 | pfnCompare,
|
---|
612 | NULL);
|
---|
613 | }
|
---|
614 | };
|
---|
615 |
|
---|
616 | #endif
|
---|
617 |
|
---|
618 |
|
---|