2 * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
30 * A chain of nodes is an abstraction used to implements complex list operations
33 * Do not use this directly. Use lists instead.
36 #ifndef __TOMMYCHAIN_H
37 #define __TOMMYCHAIN_H
39 #include "tommytypes.h"
41 /******************************************************************************/
46 * A chain of nodes is a sequence of nodes with the following properties:
47 * - It contains at least one node. A chains of zero nodes cannot exist.
48 * - The next field of the tail is of *undefined* value.
49 * - The prev field of the head is of *undefined* value.
50 * - All the other inner prev and next fields are correctly set.
52 typedef struct tommy_chain_struct
{
53 tommy_node
* head
; /**< Pointer to the head of the chain. */
54 tommy_node
* tail
; /**< Pointer to the tail of the chain. */
58 * Splices a chain in the middle of another chain.
60 tommy_inline
void tommy_chain_splice(tommy_node
* first_before
, tommy_node
* first_after
, tommy_node
* second_head
, tommy_node
* second_tail
)
62 /* set the prev list */
63 first_after
->prev
= second_tail
;
64 second_head
->prev
= first_before
;
66 /* set the next list */
67 first_before
->next
= second_head
;
68 second_tail
->next
= first_after
;
74 tommy_inline
void tommy_chain_concat(tommy_node
* first_tail
, tommy_node
* second_head
)
76 /* set the prev list */
77 second_head
->prev
= first_tail
;
79 /* set the next list */
80 first_tail
->next
= second_head
;
86 tommy_inline
void tommy_chain_merge(tommy_chain
* first
, tommy_chain
* second
, tommy_compare_func
* cmp
)
88 tommy_node
* first_i
= first
->head
;
89 tommy_node
* second_i
= second
->head
;
93 if (cmp(first_i
->data
, second_i
->data
) > 0) {
94 tommy_node
* next
= second_i
->next
;
95 if (first_i
== first
->head
) {
96 tommy_chain_concat(second_i
, first_i
);
97 first
->head
= second_i
;
99 tommy_chain_splice(first_i
->prev
, first_i
, second_i
, second_i
);
101 if (second_i
== second
->tail
)
105 if (first_i
== first
->tail
) {
106 tommy_chain_concat(first_i
, second_i
);
107 first
->tail
= second
->tail
;
110 first_i
= first_i
->next
;
116 * Merges two chains managing special degenerated cases.
117 * It's funtionally equivalent at tommy_chain_merge() but faster with already ordered chains.
119 tommy_inline
void tommy_chain_merge_degenerated(tommy_chain
* first
, tommy_chain
* second
, tommy_compare_func
* cmp
)
121 /* identify the condition first <= second */
122 if (cmp(first
->tail
->data
, second
->head
->data
) <= 0) {
123 tommy_chain_concat(first
->tail
, second
->head
);
124 first
->tail
= second
->tail
;
128 /* identify the condition second < first */
129 /* here we must be strict on comparison to keep the sort stable */
130 if (cmp(second
->tail
->data
, first
->head
->data
) < 0) {
131 tommy_chain_concat(second
->tail
, first
->head
);
132 first
->head
= second
->head
;
136 tommy_chain_merge(first
, second
, cmp
);
141 * It's a stable merge sort using power of 2 buckets, with O(N*log(N)) complexity,
142 * similar at the one used in the SGI STL libraries and in the Linux Kernel,
143 * but faster on degenerated cases like already ordered lists.
146 * http://www.sgi.com/tech/stl/stl_list.h
148 * Linux Kernel lib/list_sort.c
149 * http://lxr.linux.no/#linux+v2.6.36/lib/list_sort.c
151 tommy_inline
void tommy_chain_mergesort(tommy_chain
* chain
, tommy_compare_func
* cmp
)
154 * Bit buckets of chains.
155 * Each bucket contains 2^i nodes or it's empty.
156 * The chain at address TOMMY_BIT_MAX is an independet variable operating as "carry".
157 * We keep it in the same "bit" vector to avoid reports from the valgrind tool sgcheck.
159 tommy_chain bit
[TOMMY_SIZE_BIT
+ 1];
162 * Value stored inside the bit bucket.
163 * It's used to know which bucket is empty of full.
165 tommy_size_t counter
;
166 tommy_node
* node
= chain
->head
;
167 tommy_node
* tail
= chain
->tail
;
176 /* carry bit to add */
177 last
= &bit
[TOMMY_SIZE_BIT
];
178 bit
[TOMMY_SIZE_BIT
].head
= node
;
179 bit
[TOMMY_SIZE_BIT
].tail
= node
;
182 /* add the bit, propagating the carry */
185 while ((mask
& 1) != 0) {
186 tommy_chain_merge_degenerated(&bit
[i
], last
, cmp
);
192 /* copy the carry in the first empty bit */
195 /* add the carry in the counter */
203 /* merge the buckets */
204 i
= tommy_ctz(counter
);
209 tommy_chain_merge_degenerated(&bit
[i
+ 1], &bit
[i
], cmp
);