1 //
2 // List.cc
3 //
4 // List: A List class which holds objects of type Object.
5 //
6 // Part of the ht://Dig package <http://www.htdig.org/>
7 // Copyright (c) 1999-2004 The ht://Dig Group
8 // For copyright details, see the file COPYING in your distribution
9 // or the GNU Library General Public License (LGPL) version 2 or later
10 // <http://www.gnu.org/copyleft/lgpl.html>
11 //
12 // $Id: List.cc,v 1.9 2004/05/28 13:15:21 lha Exp $
13 //
14
15 #ifdef HAVE_CONFIG_H
16 #include "htconfig.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #include "List.h"
20
21 class listnode
22 {
23 public:
24
25 listnode *next;
26 Object *object;
27 };
28
29
30 //*********************************************************************
31 // List::List()
32 // Constructor
33 //
List()34 List::List()
35 {
36 head = tail = 0;
37 number = 0;
38 }
39
40
41 //*********************************************************************
42 // List::~List()
43 // Destructor
44 //
~List()45 List::~List()
46 {
47 Destroy();
48 }
49
50
51 //*********************************************************************
52 // void List::Release()
53 // Release all the objects from our list.
54 //
Release()55 void List::Release()
56 {
57 listnode *node;
58 while (head)
59 {
60 node = head;
61 head = head->next;
62 delete node;
63 }
64 head = tail = 0;
65 number = 0;
66 cursor.Clear();
67 }
68
69
70 //*********************************************************************
71 // void List::Destroy()
72 // Delete all the objects from our list.
73 //
Destroy()74 void List::Destroy()
75 {
76 listnode *node;
77 while (head)
78 {
79 node = head;
80 head = head->next;
81 delete node->object;
82 delete node;
83 }
84 head = tail = 0;
85 number = 0;
86 cursor.Clear();
87 }
88
89
90 //*********************************************************************
91 // void List::Add(Object *object)
92 // Add an object to the list.
93 //
Add(Object * object)94 void List::Add(Object *object)
95 {
96 listnode *node = new listnode;
97 node->next = 0;
98 node->object = object;
99 if (tail)
100 {
101 tail->next = node;
102 tail = node;
103 }
104 else
105 {
106 head = tail = node;
107 }
108
109 number++;
110 }
111
112
113 //*********************************************************************
114 // void List::Insert(Object *object, int position)
115 // Add an object to the list.
116 //
Insert(Object * object,int position)117 void List::Insert(Object *object, int position)
118 {
119 listnode *node = new listnode;
120 node->next = 0;
121 node->object = object;
122
123 listnode *ln = head;
124 listnode *prev = 0;
125
126 for (int i = 0; i < position && ln; i++, ln = ln->next)
127 prev = ln;
128 if (!ln)
129 {
130 if (tail)
131 tail->next = node;
132 tail = node;
133
134 //
135 // The list is empty. This is a simple case, then.
136 //
137 if (!head)
138 head = node;
139 }
140 else
141 {
142 if (ln == head)
143 {
144 node->next = head;
145 head = node;
146 }
147 else
148 {
149 node->next = ln;
150 prev->next = node;
151 }
152 }
153
154 cursor.current_index = -1;
155 number++;
156 }
157
158
159 //*********************************************************************
160 // void List::Assign(Object *object, int position)
161 // Assign a new value to an index.
162 //
Assign(Object * object,int position)163 void List::Assign(Object *object, int position)
164 {
165 //
166 // First make sure that there is something there!
167 //
168 while (number < position + 1)
169 {
170 Add(0);
171 }
172
173 //
174 // Now find the listnode to put the new object in
175 //
176 listnode *temp = head;
177
178 for (int i = 0; temp && i < position; i++)
179 {
180 temp = temp->next;
181 }
182
183 cursor.current_index = -1;
184 delete temp->object;
185 temp->object = object;
186 }
187
188
189 //*********************************************************************
190 // int List::Remove(Object *object)
191 // Remove an object from the list.
192 //
Remove(Object * object)193 int List::Remove(Object *object)
194 {
195 listnode *node = head;
196 listnode *prev = 0;
197 while (node)
198 {
199 if (node->object == object)
200 {
201 //
202 // Found it!
203 //
204 //
205 // If we are in the middle of a Get_Next() sequence, we need to
206 // fix up any problems with the current node.
207 //
208 if (cursor.current == node)
209 {
210 cursor.current = node->next;
211 }
212
213 if (head == tail)
214 {
215 head = tail = 0;
216 }
217 else if (head == node)
218 {
219 head = head->next;
220 }
221 else if (tail == node)
222 {
223 tail = prev;
224 tail->next = 0;
225 }
226 else
227 {
228 prev->next = node->next;
229 }
230
231 delete node;
232 number--;
233 cursor.current_index = -1;
234 return 1;
235 }
236 prev = node;
237 node = node->next;
238 }
239 return 0;
240 }
241
242 //*********************************************************************
243 //
Remove(int position,int action)244 int List::Remove(int position, int action /* = LIST_REMOVE_DESTROY */)
245 {
246 Object *o = List::operator[](position);
247 if(action == LIST_REMOVE_DESTROY) delete o;
248 return List::Remove(o);
249 }
250
251 //*********************************************************************
252 // Object *List::Get_Next()
253 // Return the next object in the list.
254 //
Get_Next(ListCursor & cursor) const255 Object *List::Get_Next(ListCursor& cursor) const
256 {
257 listnode *temp = cursor.current;
258
259 if (cursor.current)
260 {
261 cursor.prev = cursor.current;
262 cursor.current = cursor.current->next;
263 if (cursor.current_index >= 0)
264 cursor.current_index++;
265 }
266 else
267 return 0;
268 return temp->object;
269 }
270
271
272 //*********************************************************************
273 // Object *List::Get_First()
274 // Return the first object in the list.
275 //
Get_First()276 Object *List::Get_First()
277 {
278 if (head)
279 return head->object;
280 else
281 return 0;
282 }
283
284
285 //*********************************************************************
286 // int List::Index(Object *obj)
287 // Return the index of an object in the list.
288 //
Index(Object * obj)289 int List::Index(Object *obj)
290 {
291 listnode *temp = head;
292 int index = 0;
293
294 while (temp && temp->object != obj)
295 {
296 temp = temp->next;
297 index++;
298 }
299 if (index >= number)
300 return -1;
301 else
302 return index;
303 }
304
305
306 //*********************************************************************
307 // Object *List::Next(Object *prev)
308 // Return the next object in the list. Using this, the list will
309 // appear as a circular list.
310 //
Next(Object * prev)311 Object *List::Next(Object *prev)
312 {
313 listnode *node = head;
314 while (node)
315 {
316 if (node->object == prev)
317 {
318 node = node->next;
319 if (!node)
320 return head->object;
321 else
322 return node->object;
323 }
324 node = node->next;
325 }
326
327 return 0;
328 }
329
330
331 //*********************************************************************
332 // Object *List::Previous(Object *next)
333 // Return the next object in the list. Using this, the list will
334 // appear as a circular list.
335 //
Previous(Object * next)336 Object *List::Previous(Object *next)
337 {
338 listnode *node = head;
339 listnode *prev = 0;
340 while (node)
341 {
342 if (node->object == next)
343 {
344 if (!prev)
345 return 0;
346 else
347 return prev->object;
348 }
349 prev = node;
350 node = node->next;
351 }
352
353 return 0;
354 }
355
356
357 //*********************************************************************
358 // Return the nth object in the list.
359 //
Nth(ListCursor & cursor,int n) const360 const Object *List::Nth(ListCursor& cursor, int n) const
361 {
362 if (n < 0 || n >= number)
363 return 0;
364
365 listnode *temp = head;
366
367 if (cursor.current_index == n)
368 return cursor.current->object;
369
370 if (cursor.current && cursor.current_index >= 0 && n == cursor.current_index + 1)
371 {
372 cursor.prev = cursor.current;
373 cursor.current = cursor.current->next;
374 if (!cursor.current)
375 {
376 cursor.current_index = -1;
377 return 0;
378 }
379 cursor.current_index = n;
380 return cursor.current->object;
381 }
382
383 for (int i = 0; temp && i < n; i++)
384 {
385 temp = temp->next;
386 }
387
388 if (temp)
389 {
390 cursor.current_index = n;
391 cursor.current = temp;
392 return temp->object;
393 }
394 else
395 return 0;
396 }
397
398
399 //*********************************************************************
400 // Object *List::Last()
401 // Return the last object inserted.
402 //
Last()403 Object *List::Last()
404 {
405 if (tail)
406 {
407 return tail->object;
408 }
409
410 return 0;
411 }
412
413 //*********************************************************************
414 //
Pop(int action)415 Object *List::Pop(int action /* = LIST_REMOVE_DESTROY */)
416 {
417 Object *o = 0;
418 listnode *ln = head;
419 listnode *prev = 0;
420
421 if (tail) {
422 if(action == LIST_REMOVE_DESTROY) {
423 delete tail->object;
424 } else {
425 o = tail->object;
426 }
427 if(head == tail) {
428 head = tail = 0;
429 } else {
430
431 for (int i = 0; ln != tail; i++, ln = ln->next)
432 prev = ln;
433 tail = prev;
434 tail->next = 0;
435 }
436 }
437
438 return o;
439 }
440
441
442 //*********************************************************************
443 // Object *List::Copy() const
444 // Return a deep copy of the list.
445 //
Copy() const446 Object *List::Copy() const
447 {
448 List *list = new List;
449 ListCursor cursor;
450
451 Start_Get(cursor);
452 Object *obj;
453 while ((obj = Get_Next(cursor)))
454 {
455 list->Add(obj->Copy());
456 }
457 return list;
458 }
459
460
461 //*********************************************************************
462 // List &List::operator=(List &list)
463 // Return a deep copy of the list.
464 //
operator =(List & list)465 List &List::operator=(List &list)
466 {
467 Destroy();
468 list.Start_Get();
469 Object *obj;
470 while ((obj = list.Get_Next()))
471 {
472 Add(obj->Copy());
473 }
474 return *this;
475 }
476
477
478 //*********************************************************************
479 // void AppendList(List &list)
480 // Move contents of other list to the end of this list, and empty the
481 // other list.
482 //
AppendList(List & list)483 void List::AppendList(List &list)
484 {
485 // Never mind an empty list or ourselves.
486 if (list.number == 0 || &list == this)
487 return;
488
489 // Correct our pointers in head and tail.
490 if (tail)
491 {
492 // Link in other list.
493 tail->next = list.head;
494
495 // Update members for added contents.
496 number += list.number;
497 tail = list.tail;
498 }
499 else
500 {
501 head = list.head;
502 tail = list.tail;
503 number = list.number;
504 }
505
506 // Clear others members to be an empty list.
507 list.head = list.tail = 0;
508 list.cursor.current = 0;
509 list.cursor.current_index = -1;
510 list.number = 0;
511 }
512