1 /*
2 * $LynxId: HTList.c,v 1.19 2013/01/04 00:31:27 tom Exp $
3 *
4 * A small List class HTList.c
5 * ==================
6 *
7 * A list is represented as a sequence of linked nodes of type HTList.
8 * The first node is a header which contains no object.
9 * New nodes are inserted between the header and the rest of the list.
10 */
11
12 #include <HTUtils.h>
13 #include <HTList.h>
14
15 #include <LYLeaks.h>
16
17 /* Create list.
18 */
HTList_new(void)19 HTList *HTList_new(void)
20 {
21 HTList *newList;
22
23 if ((newList = typeMalloc(HTList)) == NULL)
24 outofmem(__FILE__, "HTList_new");
25
26 assert(newList != NULL);
27
28 newList->object = NULL;
29 newList->next = NULL;
30
31 return newList;
32 }
33
34 /* Delete list.
35 */
HTList_delete(HTList * me)36 void HTList_delete(HTList *me)
37 {
38 HTList *current;
39
40 while ((current = me)) {
41 me = me->next;
42 FREE(current);
43 }
44
45 return;
46 }
47
48 /* Reverse order of elements in list.
49 */
HTList_reverse(HTList * start)50 HTList *HTList_reverse(HTList *start)
51 {
52 HTList *cur, *succ;
53
54 if (!(start && start->next && (cur = start->next->next)))
55 return start;
56 start->next->next = NULL;
57 while (cur) {
58 succ = cur->next;
59 cur->next = start->next;
60 start->next = cur;
61 cur = succ;
62 }
63 return start;
64 }
65
66 /* Append a list to another.
67 *
68 * If successful, the second list will become empty but not freed.
69 */
HTList_appendList(HTList * start,HTList * tail)70 HTList *HTList_appendList(HTList *start,
71 HTList *tail)
72 {
73 HTList *temp = start;
74
75 if (!start) {
76 CTRACE((tfp,
77 "HTList: Trying to append list %p to a nonexisting list\n",
78 (void *) tail));
79 return NULL;
80 }
81 if (!(tail && tail->next))
82 return start;
83
84 while (temp->next)
85 temp = temp->next;
86
87 temp->next = tail->next;
88 tail->next = NULL; /* tail is now an empty list */
89 return start;
90 }
91
92 /* Link object to START of list (so it is pointed to by the head).
93 *
94 * Unlike HTList_addObject(), it does not malloc memory for HTList entry,
95 * it use already allocated memory which should not be free'd by any
96 * list operations (optimization).
97 */
HTList_linkObject(HTList * me,void * newObject,HTList * newNode)98 void HTList_linkObject(HTList *me, void *newObject,
99 HTList *newNode)
100 {
101 if (me) {
102 if (newNode->object == NULL && newNode->next == NULL) {
103 /* It is safe: */
104 newNode->object = newObject;
105 newNode->next = me->next;
106 me->next = newNode;
107
108 } else {
109 /*
110 * This node is already linked to some list (probably this one), so
111 * refuse changing node pointers to keep the list valid!!!
112 */
113 CTRACE((tfp, "*** HTList: Refuse linking already linked obj "));
114 CTRACE((tfp, "%p, node %p, list %p\n",
115 (void *) newObject, (void *) newNode, (void *) me));
116 }
117
118 } else {
119 CTRACE((tfp,
120 "HTList: Trying to link object %p to a nonexisting list\n",
121 newObject));
122 }
123
124 return;
125 }
126
127 /* Add object to START of list (so it is pointed to by the head).
128 */
HTList_addObject(HTList * me,void * newObject)129 void HTList_addObject(HTList *me, void *newObject)
130 {
131 HTList *newNode;
132
133 if (me) {
134 if ((newNode = typeMalloc(HTList)) == NULL)
135 outofmem(__FILE__, "HTList_addObject");
136
137 assert(newNode != NULL);
138
139 newNode->object = newObject;
140 newNode->next = me->next;
141 me->next = newNode;
142
143 } else {
144 CTRACE((tfp, "HTList: Trying to add object %p to a nonexisting list\n",
145 newObject));
146 }
147
148 return;
149 }
150
151 /* Append object to END of list (furthest from the head).
152 */
HTList_appendObject(HTList * me,void * newObject)153 void HTList_appendObject(HTList *me, void *newObject)
154 {
155 HTList *temp = me;
156
157 if (temp && newObject) {
158 while (temp->next)
159 temp = temp->next;
160 HTList_addObject(temp, newObject);
161 }
162
163 return;
164 }
165
166 /* Insert an object into the list at a specified position.
167 * If position is 0, this places the object at the head of the list
168 * and is equivalent to HTList_addObject().
169 */
HTList_insertObjectAt(HTList * me,void * newObject,int pos)170 void HTList_insertObjectAt(HTList *me, void *newObject,
171 int pos)
172 {
173 HTList *newNode;
174 HTList *temp = me;
175 HTList *prevNode;
176 int Pos = pos;
177
178 if (!temp) {
179 CTRACE((tfp, "HTList: Trying to add object %p to a nonexisting list\n",
180 newObject));
181 return;
182 }
183 if (Pos < 0) {
184 Pos = 0;
185 CTRACE((tfp, "HTList: Treating negative object position %d as %d.\n",
186 pos, Pos));
187 }
188
189 prevNode = temp;
190 while ((temp = temp->next)) {
191 if (Pos == 0) {
192 if ((newNode = typeMalloc(HTList)) == NULL)
193 outofmem(__FILE__, "HTList_addObjectAt");
194
195 assert(newNode != NULL);
196
197 newNode->object = newObject;
198 newNode->next = temp;
199 if (prevNode)
200 prevNode->next = newNode;
201 return;
202 }
203 prevNode = temp;
204 Pos--;
205 }
206 if (Pos >= 0)
207 HTList_addObject(prevNode, newObject);
208
209 return;
210 }
211
212 /* Unlink specified object from list.
213 * It does not free memory.
214 */
HTList_unlinkObject(HTList * me,void * oldObject)215 BOOL HTList_unlinkObject(HTList *me, void *oldObject)
216 {
217 HTList *temp = me;
218 HTList *prevNode;
219
220 if (temp && oldObject) {
221 while (temp->next) {
222 prevNode = temp;
223 temp = temp->next;
224 if (temp->object == oldObject) {
225 prevNode->next = temp->next;
226 temp->next = NULL;
227 temp->object = NULL;
228 return YES; /* Success */
229 }
230 }
231 }
232 return NO; /* object not found or NULL list */
233 }
234
235 /* Remove specified object from list.
236 */
HTList_removeObject(HTList * me,void * oldObject)237 BOOL HTList_removeObject(HTList *me, void *oldObject)
238 {
239 HTList *temp = me;
240 HTList *prevNode;
241
242 if (temp && oldObject) {
243 while (temp->next) {
244 prevNode = temp;
245 temp = temp->next;
246 if (temp->object == oldObject) {
247 prevNode->next = temp->next;
248 FREE(temp);
249 return YES; /* Success */
250 }
251 }
252 }
253 return NO; /* object not found or NULL list */
254 }
255
256 /* Remove object at a given position in the list, where 0 is the
257 * object pointed to by the head (returns a pointer to the element
258 * (->object) for the object, and NULL if the list is empty, or
259 * if it doesn't exist - Yuk!).
260 */
HTList_removeObjectAt(HTList * me,int position)261 void *HTList_removeObjectAt(HTList *me, int position)
262 {
263 HTList *temp = me;
264 HTList *prevNode;
265 int pos = position;
266 void *result = NULL;
267
268 if (temp != NULL && pos >= 0) {
269 prevNode = temp;
270 while ((temp = temp->next) != NULL) {
271 if (pos == 0) {
272 prevNode->next = temp->next;
273 result = temp->object;
274 FREE(temp);
275 break;
276 }
277 prevNode = temp;
278 pos--;
279 }
280 }
281
282 return result;
283 }
284
285 /* Unlink object from START of list (the Last one inserted
286 * via HTList_linkObject(), and pointed to by the head).
287 * It does not free memory.
288 */
HTList_unlinkLastObject(HTList * me)289 void *HTList_unlinkLastObject(HTList *me)
290 {
291 HTList *lastNode;
292 void *lastObject;
293
294 if (me && me->next) {
295 lastNode = me->next;
296 lastObject = lastNode->object;
297 me->next = lastNode->next;
298 lastNode->next = NULL;
299 lastNode->object = NULL;
300 return lastObject;
301
302 } else { /* Empty list */
303 return NULL;
304 }
305 }
306
307 /* Remove object from START of list (the Last one inserted
308 * via HTList_addObject(), and pointed to by the head).
309 */
HTList_removeLastObject(HTList * me)310 void *HTList_removeLastObject(HTList *me)
311 {
312 HTList *lastNode;
313 void *lastObject;
314
315 if (me && me->next) {
316 lastNode = me->next;
317 lastObject = lastNode->object;
318 me->next = lastNode->next;
319 FREE(lastNode);
320 return lastObject;
321
322 } else { /* Empty list */
323 return NULL;
324 }
325 }
326
327 /* Remove object from END of list (the First one inserted
328 * via HTList_addObject(), and furthest from the head).
329 */
HTList_removeFirstObject(HTList * me)330 void *HTList_removeFirstObject(HTList *me)
331 {
332 HTList *temp = me;
333 HTList *prevNode;
334 void *firstObject;
335
336 if (!temp)
337 return NULL;
338
339 prevNode = temp;
340 if (temp->next) {
341 while (temp->next) {
342 prevNode = temp;
343 temp = temp->next;
344 }
345 firstObject = temp->object;
346 prevNode->next = NULL;
347 FREE(temp);
348 return firstObject;
349
350 } else { /* Empty list */
351 return NULL;
352 }
353 }
354
355 /* Determine total number of objects in the list,
356 * not counting the head.
357 */
HTList_count(HTList * me)358 int HTList_count(HTList *me)
359 {
360 HTList *temp = me;
361 int count = 0;
362
363 if (temp)
364 while ((temp = temp->next))
365 count++;
366
367 return count;
368 }
369
370 /* Determine position of an object in the list (a value of 0
371 * means it is pointed to by the head; returns -1 if not found).
372 */
HTList_indexOf(HTList * me,void * object)373 int HTList_indexOf(HTList *me, void *object)
374 {
375 HTList *temp = me;
376 int position = 0;
377
378 if (temp) {
379 while ((temp = temp->next)) {
380 if (temp->object == object)
381 return position;
382 position++;
383 }
384 }
385
386 return -1; /* Object not in the list */
387 }
388
389 /* Return pointer to the object at a specified position in the list,
390 * where 0 is the object pointed to by the head (returns NULL if
391 * the list is empty, or if it doesn't exist - Yuk!).
392 */
HTList_objectAt(HTList * me,int position)393 void *HTList_objectAt(HTList *me, int position)
394 {
395 HTList *temp = me;
396 int pos = position;
397
398 if (!temp || pos < 0)
399 return NULL;
400
401 while ((temp = temp->next)) {
402 if (pos == 0)
403 return temp->object;
404 pos--;
405 }
406
407 return NULL; /* Reached the end of the list */
408 }
409