source: trunk/packages/vizservers/nanovis/Chain.cpp @ 1970

Last change on this file since 1970 was 933, checked in by gah, 16 years ago

Initial implementation of axis autoscaling

File size: 7.6 KB
Line 
1
2/*
3 * Chain.cpp --
4 *
5 * The module implements a generic linked list package.
6 *
7 *      Copyright 1991-2004 George A Howlett.
8 *
9 *      Permission is hereby granted, free of charge, to any person obtaining
10 *      a copy of this software and associated documentation files (the
11 *      "Software"), to deal in the Software without restriction, including
12 *      without limitation the rights to use, copy, modify, merge, publish,
13 *      distribute, sublicense, and/or sell copies of the Software, and to
14 *      permit persons to whom the Software is furnished to do so, subject to
15 *      the following conditions:
16 *
17 *      The above copyright notice and this permission notice shall be
18 *      included in all copies or substantial portions of the Software.
19 *
20 *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 *      EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 *      MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 *      NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 *      LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 *      OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 *      WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29#include <stdlib.h>
30#include <stdio.h>
31#include "Chain.h"
32
33typedef int (QSortCompareProc) (const void *, const void *);
34
35/*
36 *----------------------------------------------------------------------
37 *
38 * Reset --
39 *
40 *      Removes all the links from the chain, freeing the memory for each
41 *      link.  Memory pointed to by the link (clientData) is not freed.  It's
42 *      the caller's responsibility to deallocate it.
43 *
44 * Results:
45 *      None.
46 *
47 *----------------------------------------------------------------------
48 */
49void
50Chain::Reset() /* Chain to clear */
51{
52    ChainLink *oldPtr;
53    ChainLink *linkPtr = _head;
54
55    while (linkPtr != NULL) {
56        oldPtr = linkPtr;
57        linkPtr = linkPtr->Next();
58        delete oldPtr;
59    }
60    Init();
61}
62
63/*
64 *----------------------------------------------------------------------
65 *
66 * LinkAfter --
67 *
68 *      Inserts a link after another link.  If afterPtr is NULL, then the new
69 *      link is prepended to the beginning of the chain.
70 *
71 * Results:
72 *      None.
73 *
74 *----------------------------------------------------------------------
75 */
76void
77Chain::LinkAfter(ChainLink *linkPtr, ChainLink *afterPtr)
78{
79    if (_head == NULL) {
80        _tail = _head = linkPtr;
81    } else {
82        if (afterPtr == NULL) {
83            /* Prepend to the front of the chain */
84            linkPtr->_next = _head;
85            linkPtr->_prev = NULL;
86            _head->_prev = linkPtr;
87            _head = linkPtr;
88        } else {
89            linkPtr->_next = afterPtr->Next();
90            linkPtr->_prev = afterPtr;
91            if (afterPtr == _tail) {
92                _tail = linkPtr;
93            } else {
94                afterPtr->Next()->_prev = linkPtr;
95            }
96            afterPtr->_next = linkPtr;
97        }
98    }
99    _nLinks++;
100}
101
102/*
103 *----------------------------------------------------------------------
104 *
105 * LinkBefore --
106 *
107 *      Inserts a new link preceding a given link in a chain.  If beforePtr is
108 *      NULL, then the new link is placed at the beginning of the list.
109 *
110 * Results:
111 *      None.
112 *
113 *----------------------------------------------------------------------
114 */
115void
116Chain::LinkBefore(
117    ChainLink *linkPtr,         /* New entry to be inserted */
118    ChainLink *beforePtr)       /* Entry to link before */
119{
120    if (_head == NULL) {
121        _tail = _head = linkPtr;
122    } else {
123        if (beforePtr == NULL) {
124            /* Append to the end of the chain. */
125            linkPtr->_next = NULL;
126            linkPtr->_prev = _tail;
127            _tail->_next = linkPtr;
128            _tail = linkPtr;
129        } else {
130            linkPtr->_prev = beforePtr->Prev();
131            linkPtr->_next = beforePtr;
132            if (beforePtr == _head) {
133                _head = linkPtr;
134            } else {
135                beforePtr->Prev()->_next = linkPtr;
136            }
137            beforePtr->_prev = linkPtr;
138        }
139    }
140    _nLinks++;
141}
142
143/*
144 *----------------------------------------------------------------------
145 *
146 * Unlink --
147 *
148 *      Unlinks a link from the chain. The link is not deallocated,
149 *      but only removed from the chain.
150 *
151 * Results:
152 *      None.
153 *
154 *----------------------------------------------------------------------
155 */
156void
157Chain::Unlink(ChainLink *linkPtr)
158{
159    bool unlinked;              /* Indicates if the link is actually removed
160                                 * from the chain. */
161
162    unlinked = false;
163    if (_head == linkPtr) {
164        _head = linkPtr->Next();
165        unlinked = true;
166    }
167    if (_tail == linkPtr) {
168        _tail = linkPtr->Prev();
169        unlinked = true;
170    }
171    if (linkPtr->Next() != NULL) {
172        linkPtr->Next()->_prev = linkPtr->Prev();
173        unlinked = true;
174    }
175    if (linkPtr->Prev() != NULL) {
176        linkPtr->Prev()->_next = linkPtr->Next();
177        unlinked = true;
178    }
179    if (unlinked) {
180        _nLinks--;
181    }
182    linkPtr->_prev = linkPtr->_next = NULL;
183}
184
185/*
186 *----------------------------------------------------------------------
187 *
188 * DeleteLink --
189 *
190 *      Unlinks and frees the given link from the chain.  It's assumed that
191 *      the link belong to the chain. No error checking is performed to verify
192 *      this.
193 *
194 * Results:
195 *      None.
196 *
197 *----------------------------------------------------------------------
198 */
199void
200Chain::DeleteLink(ChainLink *linkPtr)
201{
202    Unlink(linkPtr);
203    delete linkPtr;
204}
205
206/*
207 *----------------------------------------------------------------------
208 *
209 * Append --
210 *
211 *      Creates and new link with the given data and appends it to the end of
212 *      the chain.
213 *
214 * Results:
215 *      Returns a pointer to the link created.
216 *
217 *----------------------------------------------------------------------
218 */
219ChainLink *
220Chain::Append(void *clientData)
221{
222    ChainLink *linkPtr;
223
224    linkPtr = new ChainLink(clientData);
225    LinkBefore(linkPtr, (ChainLink *)NULL);
226    return linkPtr;
227}
228
229/*
230 *----------------------------------------------------------------------
231 *
232 * Prepend --
233 *
234 *      Creates and new link with the given data and prepends it to beginning
235 *      of the chain.
236 *
237 * Results:
238 *      Returns a pointer to the link created.
239 *
240 *----------------------------------------------------------------------
241 */
242ChainLink  *
243Chain::Prepend(void *clientData)
244{
245    ChainLink *linkPtr;
246
247    linkPtr = new ChainLink(clientData);
248    LinkAfter(linkPtr, (ChainLink *)NULL);
249    return linkPtr;
250}
251
252/*
253 *----------------------------------------------------------------------
254 *
255 * GetNthLink --
256 *
257 *      Find the link at the given position in the chain.
258 *
259 * Results:
260 *      Returns the pointer to the link, if that numbered link
261 *      exists. Otherwise NULL.
262 *
263 *----------------------------------------------------------------------
264 */
265ChainLink *
266Chain::GetNthLink(long position) /* Index of link to select from front or back
267                                  * of the chain. */
268{
269    ChainLink *linkPtr;
270
271    for (linkPtr = _head; linkPtr != NULL; linkPtr = linkPtr->Next()) {
272        if (position == 0) {
273            return linkPtr;
274        }
275        position--;
276    }
277    return NULL;
278}
279
280/*
281 *----------------------------------------------------------------------
282 *
283 * Sort --
284 *
285 *      Sorts the chain according to the given comparison routine. 
286 *
287 * Results:
288 *      None.
289 *
290 * Side Effects:
291 *      The chain is reordered.
292 *
293 *----------------------------------------------------------------------
294 */
295
296void
297Chain::Sort(ChainCompareProc *proc)
298{
299    ChainLink *linkPtr;
300    long i;
301
302    if (_nLinks < 2) {
303        return;
304    }
305    ChainLink **linkArr = new ChainLink *[_nLinks + 1];
306    if (linkArr == NULL) {
307        return;                 /* Out of memory. */
308    }
309    i = 0;
310    for (linkPtr = _head; linkPtr != NULL; linkPtr = linkPtr->Next()) {
311        linkArr[i++] = linkPtr;
312    }
313    qsort((char *)linkArr, _nLinks, sizeof(ChainLink *),
314          (QSortCompareProc *)proc);
315
316    /* Rethread the chain. */
317    linkPtr = linkArr[0];
318    _head = linkPtr;
319    linkPtr->_prev = NULL;
320    for (i = 1; i < _nLinks; i++) {
321        linkPtr->_next = linkArr[i];
322        linkPtr->Next()->_prev = linkPtr;
323        linkPtr = linkPtr->Next();
324    }
325    _tail = linkPtr;
326    linkPtr->_next = NULL;
327    delete [] linkArr;
328}
329
Note: See TracBrowser for help on using the repository browser.