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