2 Lightweight C Container Library
4 Copyright (c) 2002 Tobias Koenig <tokoe@kde.org>
6 Original code was written by Chris Schlaeger <cs@kde.org>
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
31 struct container_info
{
33 CONTAINER currentNode
;
36 typedef struct container_info T_CONTAINER_INFO
;
37 typedef struct container_info
* CONTAINER_INFO
;
39 #define rpterr(x) fprintf(stderr, "%s\n", x)
41 CONTAINER
new_ctnr(void)
46 rootNode
= (CONTAINER
)malloc(sizeof(T_CONTAINER
));
48 info
= (CONTAINER_INFO
)malloc(sizeof(T_CONTAINER_INFO
));
50 info
->currentNode
= rootNode
;
52 rootNode
->next
= rootNode
;
53 rootNode
->prev
= rootNode
;
54 rootNode
->data
= info
;
60 void zero_destr_ctnr(CONTAINER rootNode
, DESTR_FUNC destr_func
)
64 if (rootNode
== NIL
|| destr_func
== NIL
) {
65 rpterr("destr_ctnr: NIL argument");
69 for (counter
= level_ctnr(rootNode
); counter
> -1; --counter
)
70 destr_func(pop_ctnr(rootNode
));
72 assert(rootNode
->data
);
82 void empty_ctnr(CONTAINER rootNode
)
86 if (rootNode
== NIL
) {
87 rpterr("empty_ctnr: NIL argument");
91 for ( i
= level_ctnr( rootNode
); i
>= 0; --i
)
92 free( pop_ctnr( rootNode
) );
98 INDEX
level_ctnr(CONTAINER rootNode
)
100 if (rootNode
== NIL
) {
101 rpterr("level_ctnr: NIL argument");
105 return ((CONTAINER_INFO
)rootNode
->data
)->count
;
108 /* This function is never used */
110 void insert_ctnr(CONTAINER rootNode
, void* object
, INDEX pos
)
115 if (rootNode
== NIL
|| object
== NIL
) {
116 rpterr("insert_ctnr: NIL argument");
120 for (it
= rootNode
->next
; it
!= rootNode
; it
= it
->next
) {
121 if (counter
== pos
) {
122 CONTAINER newNode
= (CONTAINER
)malloc(sizeof(T_CONTAINER
));
125 newNode
->next
= it
->next
;
126 it
->next
->prev
= newNode
;
129 newNode
->data
= object
;
130 ((CONTAINER_INFO
)rootNode
->data
)->count
++;
139 void push_ctnr(CONTAINER rootNode
, void* object
)
143 if (rootNode
== NIL
|| object
== NIL
) {
144 rpterr("push_ctnr: NIL argument");
148 newNode
= (CONTAINER
)malloc(sizeof(T_CONTAINER
));
149 newNode
->next
= rootNode
;
150 newNode
->prev
= rootNode
->prev
;
151 rootNode
->prev
->next
= newNode
;
152 rootNode
->prev
= newNode
;
154 newNode
->data
= object
;
155 ((CONTAINER_INFO
)rootNode
->data
)->count
++;
158 /* This function is never used */
160 void* remove_at_ctnr(CONTAINER rootNode
, INDEX pos
)
166 if (rootNode
== NIL
) {
167 rpterr("remove_ctnr: NIL argument");
171 for (it
= rootNode
->next
; it
!= rootNode
; it
= it
->next
) {
172 if (counter
== pos
) {
175 it
->prev
->next
= it
->next
;
176 it
->next
->prev
= it
->prev
;
180 ((CONTAINER_INFO
)rootNode
->data
)->count
--;
190 /* This function is only used within ccont.c */
192 void* pop_ctnr(CONTAINER rootNode
)
197 if (rootNode
== NIL
) {
198 rpterr("pop_ctnr: NIL argument");
202 if (rootNode
->next
== rootNode
)
205 ptr
= rootNode
->next
;
208 rootNode
->next
= ptr
->next
;
209 ptr
->next
->prev
= rootNode
;
211 ((CONTAINER_INFO
)rootNode
->data
)->count
--;
219 void* get_ctnr(CONTAINER rootNode
, INDEX pos
)
224 if (rootNode
== NIL
) {
225 rpterr("get_ctnr: NIL argument");
229 for (it
= rootNode
->next
; it
!= rootNode
; it
= it
->next
) {
239 /* This should return a reference to the node found instead of its index.
240 The index is never used, except as an argument to a O(n) function to
241 get a reference to the node. */
243 INDEX
search_ctnr(CONTAINER rootNode
, COMPARE_FUNC compare_func
, void* pattern
)
248 if (rootNode
== NIL
|| compare_func
== NIL
|| pattern
== NIL
) {
249 rpterr("search_ctnr: NIL argument");
253 for (it
= rootNode
->next
; it
!= rootNode
; it
= it
->next
) {
254 if (compare_func(pattern
, it
->data
) == 0)
263 /* This function is never used */
265 void swap_ctnr(CONTAINER rootNode
, INDEX pos1
, INDEX pos2
)
267 CONTAINER it
, node1
= 0, node2
= 0;
272 if (rootNode
== NIL
) {
273 rpterr("swap_ctnr: NIL argument");
280 for (it
= rootNode
->next
; it
!= rootNode
; it
= it
->next
) {
281 if (counter
== pos1
) {
287 if (counter
== pos2
) {
298 tmpData
= node1
->data
;
299 node1
->data
= node2
->data
;
300 node2
->data
= tmpData
;
305 void bsort_ctnr(CONTAINER rootNode
, COMPARE_FUNC compare_func
)
307 /* Use mergesort adapted from http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.c */
309 CONTAINER p
, q
, e
, tail
, oldhead
;
310 INDEX insize
, nmerges
, psize
, qsize
, i
;
312 if (rootNode
== NIL
|| compare_func
== NIL
) {
313 rpterr("bsort_ctnr: NIL argument");
317 if (level_ctnr(rootNode
) == 0) {
318 /* Nothing to sort */
326 oldhead
= rootNode
; /* only used for circular linkage */
327 rootNode
->next
= NULL
;
330 nmerges
= 0; /* count number of merges we do in this pass */
333 nmerges
++; /* there exists a merge to be done */
334 /* step `insize' places along from p */
337 for (i
= 0; i
< insize
; i
++) {
339 q
= (q
->next
== oldhead
? NULL
: q
->next
);
343 /* if q hasn't fallen off end, we have two lists to merge */
346 /* now we have two lists; merge them */
347 while (psize
> 0 || (qsize
> 0 && q
)) {
348 /* decide whether next element of merge comes from p or q */
351 /* p is empty; e must come from q. */
352 e
= q
; q
= q
->next
; qsize
--;
353 if (q
== oldhead
) q
= NULL
;
354 } else if (qsize
== 0 || !q
) {
356 /* q is empty; e must come from p. */
357 e
= p
; p
= p
->next
; psize
--;
358 if (p
== oldhead
) p
= NULL
;
359 } else if (compare_func(p
,q
) <= 0) {
360 /* First element of p is lower (or same);
361 * e must come from p. */
362 e
= p
; p
= p
->next
; psize
--;
363 if (p
== oldhead
) p
= NULL
;
365 /* First element of q is lower; e must come from q. */
366 e
= q
; q
= q
->next
; qsize
--;
367 if (q
== oldhead
) q
= NULL
;
370 /* add the next element to the merged list */
382 /* now p has stepped `insize' places along, and q has too */
387 tail
->next
= rootNode
;
388 rootNode
->prev
= tail
;
390 /* If we have done only one merge, we're finished. */
391 if (nmerges
<= 1) { /* allow for nmerges==0, the empty list case */
395 /* Otherwise repeat, merging lists twice the size */
401 void* first_ctnr(CONTAINER rootNode
)
403 if (rootNode
== NIL
) {
404 rpterr("first_ctnr: NIL argument");
408 if (rootNode
->next
== rootNode
)
411 ((CONTAINER_INFO
)rootNode
->data
)->currentNode
= rootNode
->next
;
413 return rootNode
->next
->data
;
417 void* next_ctnr(CONTAINER rootNode
)
421 if (rootNode
== NIL
) {
422 rpterr("next_ctnr: NIL argument");
426 info
= (CONTAINER_INFO
)rootNode
->data
;
428 if (info
->currentNode
->next
== rootNode
)
431 info
->currentNode
= info
->currentNode
->next
;
433 return info
->currentNode
->data
;
437 void* remove_ctnr(CONTAINER rootNode
)
439 CONTAINER currentNode
, tmp
;
443 if (rootNode
== NIL
) {
444 rpterr("remove_curr_ctnr: NIL argument");
448 info
= (CONTAINER_INFO
)rootNode
->data
;
449 currentNode
= info
->currentNode
;
451 if (currentNode
== rootNode
) { /* should never happen */
452 rpterr("remove_curr_ctnr: delete root node");
456 retval
= currentNode
->data
;
457 tmp
= currentNode
->prev
;
459 currentNode
->prev
->next
= currentNode
->next
;
460 currentNode
->next
->prev
= currentNode
->prev
;
465 info
->currentNode
= tmp
;