source: trunk/src/objects/RpChain.c @ 6303

Last change on this file since 6303 was 5673, checked in by ldelgass, 9 years ago

Fix line endings, set eol-style to native on all C/C++ sources.

  • Property svn:eol-style set to native
File size: 11.4 KB
Line 
1/*
2 * bltChain.c --
3 *
4 *  The module implements a generic linked list package.
5 *
6 * Copyright 1991-1998 Lucent Technologies, Inc.
7 *
8 * Permission to use, copy, modify, and distribute this software and
9 * its documentation for any purpose and without fee is hereby
10 * granted, provided that the above copyright notice appear in all
11 * copies and that both that the copyright notice and warranty
12 * disclaimer appear in supporting documentation, and that the names
13 * of Lucent Technologies any of their entities not be used in
14 * advertising or publicity pertaining to distribution of the software
15 * without specific, written prior permission.
16 *
17 * Lucent Technologies disclaims all warranties with regard to this
18 * software, including all implied warranties of merchantability and
19 * fitness.  In no event shall Lucent Technologies be liable for any
20 * special, indirect or consequential damages or any damages
21 * whatsoever resulting from loss of use, data or profits, whether in
22 * an action of contract, negligence or other tortuous action, arising
23 * out of or in connection with the use or performance of this
24 * software.
25 */
26
27#include "RpInt.h"
28#include "RpChain.h"
29
30#ifndef ALIGN
31#define ALIGN(a) \
32    (((size_t)a + (sizeof(double) - 1)) & (~(sizeof(double) - 1)))
33#endif /* ALIGN */
34
35/*
36 *----------------------------------------------------------------------
37 *
38 * Rp_ChainCreate --
39 *
40 *  Creates a new linked list (chain) structure and initializes
41 *  its pointers;
42 *
43 * Results:
44 *  Returns a pointer to the newly created chain structure.
45 *
46 *----------------------------------------------------------------------
47 */
48Rp_Chain *
49Rp_ChainCreate()
50{
51    Rp_Chain *chainPtr;
52
53    chainPtr = (Rp_Chain *) Rp_Malloc(sizeof(Rp_Chain));
54    if (chainPtr != NULL) {
55        Rp_ChainInit(chainPtr);
56    }
57    return chainPtr;
58}
59
60/*
61 *----------------------------------------------------------------------
62 *
63 * Rp_ChainAllocLink --
64 *
65 *  Creates a new chain link.  Unlink Rp_ChainNewLink, this
66 *  routine also allocates extra memory in the node for data.
67 *
68 * Results:
69 *  The return value is the pointer to the newly created entry.
70 *
71 *----------------------------------------------------------------------
72 */
73Rp_ChainLink *
74Rp_ChainAllocLink(extraSize)
75    unsigned int extraSize;
76{
77    Rp_ChainLink *linkPtr;
78    unsigned int linkSize;
79
80    linkSize = ALIGN(sizeof(Rp_ChainLink));
81    linkPtr = Rp_Calloc(1, linkSize + extraSize);
82    assert(linkPtr);
83    if (extraSize > 0) {
84        /* Point clientData at the memory beyond the normal structure. */
85        linkPtr->clientData = (ClientData)((char *)linkPtr + linkSize);
86    }
87    return linkPtr;
88}
89
90/*
91 *----------------------------------------------------------------------
92 *
93 * Rp_ChainNewLink --
94 *
95 *  Creates a new link.
96 *
97 * Results:
98 *  The return value is the pointer to the newly created link.
99 *
100 *----------------------------------------------------------------------
101 */
102Rp_ChainLink *
103Rp_ChainNewLink()
104{
105    Rp_ChainLink *linkPtr;
106
107    linkPtr = (Rp_ChainLink *) Rp_Malloc(sizeof(Rp_ChainLink));
108    assert(linkPtr);
109    linkPtr->clientData = NULL;
110    linkPtr->nextPtr = linkPtr->prevPtr = NULL;
111    return linkPtr;
112}
113
114/*
115 *----------------------------------------------------------------------
116 *
117 * Rp_ChainReset --
118 *
119 *  Removes all the links from the chain, freeing the memory for
120 *  each link.  Memory pointed to by the link (clientData) is not
121 *  freed.  It's the caller's responsibility to deallocate it.
122 *
123 * Results:
124 *  None.
125 *
126 *----------------------------------------------------------------------
127 */
128void
129Rp_ChainReset(chainPtr)
130    Rp_Chain *chainPtr; /* Chain to clear */
131{
132    if (chainPtr != NULL) {
133        Rp_ChainLink *oldPtr;
134        Rp_ChainLink *linkPtr = chainPtr->headPtr;
135
136        while (linkPtr != NULL) {
137            oldPtr = linkPtr;
138            linkPtr = linkPtr->nextPtr;
139            Rp_Free(oldPtr);
140        }
141        Rp_ChainInit(chainPtr);
142    }
143}
144
145/*
146 *----------------------------------------------------------------------
147 *
148 * Rp_ChainDestroy
149 *
150 *     Frees all the nodes from the chain and deallocates the memory
151 *     allocated for the chain structure itself.  It's assumed that
152 *     the chain was previous allocated by Rp_ChainCreate.
153 *
154 * Results:
155 *      None.
156 *
157 *----------------------------------------------------------------------
158 */
159void
160Rp_ChainDestroy(chainPtr)
161    Rp_Chain *chainPtr;
162{
163    if (chainPtr != NULL) {
164        Rp_ChainReset(chainPtr);
165        Rp_Free(chainPtr);
166    }
167}
168
169/*
170 *----------------------------------------------------------------------
171 *
172 * Rp_ChainInit --
173 *
174 *  Initializes a linked list.
175 *
176 * Results:
177 *  None.
178 *
179 *----------------------------------------------------------------------
180 */
181void
182Rp_ChainInit(chainPtr)
183    Rp_Chain *chainPtr;
184{
185    chainPtr->nLinks = 0;
186    chainPtr->headPtr = chainPtr->tailPtr = NULL;
187}
188
189/*
190 *----------------------------------------------------------------------
191 *
192 * Rp_ChainLinkAfter --
193 *
194 *  Inserts an entry following a given entry.
195 *
196 * Results:
197 *  None.
198 *
199 *----------------------------------------------------------------------
200 */
201void
202Rp_ChainLinkAfter(chainPtr, linkPtr, afterPtr)
203    Rp_Chain *chainPtr;
204    Rp_ChainLink *linkPtr, *afterPtr;
205{
206    if (chainPtr->headPtr == NULL) {
207        chainPtr->tailPtr = chainPtr->headPtr = linkPtr;
208    } else {
209        if (afterPtr == NULL) {
210            /* Prepend to the front of the chain */
211            linkPtr->nextPtr = chainPtr->headPtr;
212            linkPtr->prevPtr = NULL;
213            chainPtr->headPtr->prevPtr = linkPtr;
214            chainPtr->headPtr = linkPtr;
215        } else {
216            linkPtr->nextPtr = afterPtr->nextPtr;
217            linkPtr->prevPtr = afterPtr;
218            if (afterPtr == chainPtr->tailPtr) {
219                chainPtr->tailPtr = linkPtr;
220            } else {
221                afterPtr->nextPtr->prevPtr = linkPtr;
222            }
223            afterPtr->nextPtr = linkPtr;
224        }
225    }
226    chainPtr->nLinks++;
227}
228
229/*
230 *----------------------------------------------------------------------
231 *
232 * Rp_ChainLinkBefore --
233 *
234 *  Inserts a link preceding a given link.
235 *
236 * Results:
237 *  None.
238 *
239 *----------------------------------------------------------------------
240 */
241void
242Rp_ChainLinkBefore(chainPtr, linkPtr, beforePtr)
243    Rp_Chain *chainPtr;         /* Chain to contain new entry */
244    Rp_ChainLink *linkPtr;      /* New entry to be inserted */
245    Rp_ChainLink *beforePtr;    /* Entry to link before */
246{
247    if (chainPtr->headPtr == NULL) {
248        chainPtr->tailPtr = chainPtr->headPtr = linkPtr;
249    } else {
250        if (beforePtr == NULL) {
251            /* Append to the end of the chain. */
252            linkPtr->nextPtr = NULL;
253            linkPtr->prevPtr = chainPtr->tailPtr;
254            chainPtr->tailPtr->nextPtr = linkPtr;
255            chainPtr->tailPtr = linkPtr;
256        } else {
257            linkPtr->prevPtr = beforePtr->prevPtr;
258            linkPtr->nextPtr = beforePtr;
259            if (beforePtr == chainPtr->headPtr) {
260                chainPtr->headPtr = linkPtr;
261            } else {
262                beforePtr->prevPtr->nextPtr = linkPtr;
263            }
264            beforePtr->prevPtr = linkPtr;
265        }
266    }
267    chainPtr->nLinks++;
268}
269
270/*
271 *----------------------------------------------------------------------
272 *
273 * Rp_ChainUnlinkLink --
274 *
275 *      Unlinks a link from the chain. The link is not deallocated,
276 *      but only removed from the chain.
277 *
278 * Results:
279 *      None.
280 *
281 *----------------------------------------------------------------------
282 */
283void
284Rp_ChainUnlinkLink(chainPtr, linkPtr)
285    Rp_Chain *chainPtr;
286    Rp_ChainLink *linkPtr;
287{
288    int unlinked;       /* Indicates if the link is actually
289                         * removed from the chain. */
290
291    unlinked = FALSE;
292    if (chainPtr->headPtr == linkPtr) {
293        chainPtr->headPtr = linkPtr->nextPtr;
294        unlinked = TRUE;
295    }
296    if (chainPtr->tailPtr == linkPtr) {
297        chainPtr->tailPtr = linkPtr->prevPtr;
298        unlinked = TRUE;
299    }
300    if (linkPtr->nextPtr != NULL) {
301        linkPtr->nextPtr->prevPtr = linkPtr->prevPtr;
302        unlinked = TRUE;
303    }
304    if (linkPtr->prevPtr != NULL) {
305        linkPtr->prevPtr->nextPtr = linkPtr->nextPtr;
306        unlinked = TRUE;
307    }
308    if (unlinked) {
309        chainPtr->nLinks--;
310    }
311    linkPtr->prevPtr = linkPtr->nextPtr = NULL;
312}
313
314/*
315 *----------------------------------------------------------------------
316 *
317 * Rp_ChainDeleteLink --
318 *
319 *  Unlinks and also frees the given link.
320 *
321 * Results:
322 *  None.
323 *
324 *----------------------------------------------------------------------
325 */
326void
327Rp_ChainDeleteLink(chainPtr, linkPtr)
328    Rp_Chain *chainPtr;
329    Rp_ChainLink *linkPtr;
330{
331    Rp_ChainUnlinkLink(chainPtr, linkPtr);
332    Rp_Free(linkPtr);
333}
334
335Rp_ChainLink *
336Rp_ChainAppend(chainPtr, clientData)
337    Rp_Chain *chainPtr;
338    ClientData clientData;
339{
340    Rp_ChainLink *linkPtr;
341
342    linkPtr = Rp_ChainNewLink();
343    Rp_ChainLinkBefore(chainPtr, linkPtr, (Rp_ChainLink *)NULL);
344    Rp_ChainSetValue(linkPtr, clientData);
345    return linkPtr;
346}
347
348Rp_ChainLink *
349Rp_ChainPrepend(chainPtr, clientData)
350    Rp_Chain *chainPtr;
351    ClientData clientData;
352{
353    Rp_ChainLink *linkPtr;
354
355    linkPtr = Rp_ChainNewLink();
356    Rp_ChainLinkAfter(chainPtr, linkPtr, (Rp_ChainLink *)NULL);
357    Rp_ChainSetValue(linkPtr, clientData);
358    return linkPtr;
359}
360
361/*
362 *----------------------------------------------------------------------
363 *
364 * Rp_ChainGetNthLink --
365 *
366 *  Find the link at the given position in the chain.
367 *
368 * Results:
369 *  Returns the pointer to the link, if that numbered link
370 *  exists. Otherwise NULL.
371 *
372 *----------------------------------------------------------------------
373 */
374Rp_ChainLink *
375Rp_ChainGetNthLink(chainPtr, position)
376    Rp_Chain *chainPtr; /* Chain to traverse */
377    int position;       /* Index of link to select from front
378                         * or back of the chain. */
379{
380    Rp_ChainLink *linkPtr;
381
382    if (chainPtr != NULL) {
383        for (linkPtr = chainPtr->headPtr; linkPtr != NULL;
384            linkPtr = linkPtr->nextPtr) {
385            if (position == 0) {
386                return linkPtr;
387            }
388            position--;
389        }
390    }
391    return NULL;
392}
393
394/*
395 *----------------------------------------------------------------------
396 *
397 * Rp_ChainSort --
398 *
399 *  Sorts the chain according to the given comparison routine.
400 *
401 * Results:
402 *  None.
403 *
404 * Side Effects:
405 *  The chain is reordered.
406 *
407 *----------------------------------------------------------------------
408 */
409void
410Rp_ChainSort(chainPtr, proc)
411    Rp_Chain *chainPtr; /* Chain to traverse */
412    Rp_ChainCompareProc *proc;
413{
414    Rp_ChainLink **linkArr;
415    register Rp_ChainLink *linkPtr;
416    register int i;
417
418    if (chainPtr->nLinks < 2) {
419        return;
420    }
421    linkArr = (Rp_ChainLink **) Rp_Malloc(sizeof(Rp_ChainLink *) * (chainPtr->nLinks + 1));
422    if (linkArr == NULL) {
423        return;         /* Out of memory. */
424    }
425    i = 0;
426    for (linkPtr = chainPtr->headPtr; linkPtr != NULL;
427         linkPtr = linkPtr->nextPtr) {
428        linkArr[i++] = linkPtr;
429    }
430    qsort((char *)linkArr, chainPtr->nLinks, sizeof(Rp_ChainLink *),
431        (QSortCompareProc *)proc);
432
433    /* Rethread the chain. */
434    linkPtr = linkArr[0];
435    chainPtr->headPtr = linkPtr;
436    linkPtr->prevPtr = NULL;
437    for (i = 1; i < chainPtr->nLinks; i++) {
438        linkPtr->nextPtr = linkArr[i];
439        linkPtr->nextPtr->prevPtr = linkPtr;
440        linkPtr = linkPtr->nextPtr;
441    }
442    chainPtr->tailPtr = linkPtr;
443    linkPtr->nextPtr = NULL;
444    Rp_Free(linkArr);
445}
Note: See TracBrowser for help on using the repository browser.