1*4882a593Smuzhiyun /* x-list.c
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun * Copyright (c) 2002-2012 Apple Inc. All rights reserved.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person
6*4882a593Smuzhiyun * obtaining a copy of this software and associated documentation files
7*4882a593Smuzhiyun * (the "Software"), to deal in the Software without restriction,
8*4882a593Smuzhiyun * including without limitation the rights to use, copy, modify, merge,
9*4882a593Smuzhiyun * publish, distribute, sublicense, and/or sell copies of the Software,
10*4882a593Smuzhiyun * and to permit persons to whom the Software is furnished to do so,
11*4882a593Smuzhiyun * subject to the following conditions:
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * The above copyright notice and this permission notice shall be
14*4882a593Smuzhiyun * included in all copies or substantial portions of the Software.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19*4882a593Smuzhiyun * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
20*4882a593Smuzhiyun * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21*4882a593Smuzhiyun * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22*4882a593Smuzhiyun * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23*4882a593Smuzhiyun * DEALINGS IN THE SOFTWARE.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * Except as contained in this notice, the name(s) of the above
26*4882a593Smuzhiyun * copyright holders shall not be used in advertising or otherwise to
27*4882a593Smuzhiyun * promote the sale, use or other dealings in this Software without
28*4882a593Smuzhiyun * prior written authorization.
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
32*4882a593Smuzhiyun #include <dix-config.h>
33*4882a593Smuzhiyun #endif
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include "x-list.h"
36*4882a593Smuzhiyun #include <stdlib.h>
37*4882a593Smuzhiyun #include <assert.h>
38*4882a593Smuzhiyun #include <pthread.h>
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* Allocate in ~4k blocks */
41*4882a593Smuzhiyun #define NODES_PER_BLOCK 508
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun typedef struct x_list_block_struct x_list_block;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun struct x_list_block_struct {
46*4882a593Smuzhiyun x_list l[NODES_PER_BLOCK];
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static x_list *freelist;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun static pthread_mutex_t freelist_lock = PTHREAD_MUTEX_INITIALIZER;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun static inline void
list_free_1(x_list * node)54*4882a593Smuzhiyun list_free_1(x_list *node)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun node->next = freelist;
57*4882a593Smuzhiyun freelist = node;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun X_EXTERN void
X_PFX(list_free_1)61*4882a593Smuzhiyun X_PFX(list_free_1) (x_list * node) {
62*4882a593Smuzhiyun assert(node != NULL);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun pthread_mutex_lock(&freelist_lock);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun list_free_1(node);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun pthread_mutex_unlock(&freelist_lock);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun X_EXTERN void
X_PFX(list_free)72*4882a593Smuzhiyun X_PFX(list_free) (x_list * lst) {
73*4882a593Smuzhiyun x_list *next;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun pthread_mutex_lock(&freelist_lock);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun for (; lst != NULL; lst = next) {
78*4882a593Smuzhiyun next = lst->next;
79*4882a593Smuzhiyun list_free_1(lst);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun pthread_mutex_unlock(&freelist_lock);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_prepend)86*4882a593Smuzhiyun X_PFX(list_prepend) (x_list * lst, void *data) {
87*4882a593Smuzhiyun x_list *node;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun pthread_mutex_lock(&freelist_lock);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (freelist == NULL) {
92*4882a593Smuzhiyun x_list_block *b;
93*4882a593Smuzhiyun int i;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun b = malloc(sizeof(x_list_block));
96*4882a593Smuzhiyun assert(b != NULL);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun for (i = 0; i < NODES_PER_BLOCK - 1; i++)
99*4882a593Smuzhiyun b->l[i].next = &(b->l[i + 1]);
100*4882a593Smuzhiyun b->l[i].next = NULL;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun freelist = b->l;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun node = freelist;
106*4882a593Smuzhiyun freelist = node->next;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun pthread_mutex_unlock(&freelist_lock);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun node->next = lst;
111*4882a593Smuzhiyun node->data = data;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun return node;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_append)117*4882a593Smuzhiyun X_PFX(list_append) (x_list * lst, void *data) {
118*4882a593Smuzhiyun x_list *head = lst;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (lst == NULL)
121*4882a593Smuzhiyun return X_PFX(list_prepend) (NULL, data);
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun while (lst->next != NULL)
124*4882a593Smuzhiyun lst = lst->next;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun lst->next = X_PFX(list_prepend) (NULL, data);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun return head;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_reverse)132*4882a593Smuzhiyun X_PFX(list_reverse) (x_list * lst) {
133*4882a593Smuzhiyun x_list *head = NULL, *next;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun while (lst != NULL)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun next = lst->next;
138*4882a593Smuzhiyun lst->next = head;
139*4882a593Smuzhiyun head = lst;
140*4882a593Smuzhiyun lst = next;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun return head;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_find)147*4882a593Smuzhiyun X_PFX(list_find) (x_list * lst, void *data) {
148*4882a593Smuzhiyun for (; lst != NULL; lst = lst->next) {
149*4882a593Smuzhiyun if (lst->data == data)
150*4882a593Smuzhiyun return lst;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun return NULL;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_nth)157*4882a593Smuzhiyun X_PFX(list_nth) (x_list * lst, int n) {
158*4882a593Smuzhiyun while (n-- > 0 && lst != NULL)
159*4882a593Smuzhiyun lst = lst->next;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun return lst;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_pop)165*4882a593Smuzhiyun X_PFX(list_pop) (x_list * lst, void **data_ret) {
166*4882a593Smuzhiyun void *data = NULL;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun if (lst != NULL) {
169*4882a593Smuzhiyun x_list *tem = lst;
170*4882a593Smuzhiyun data = lst->data;
171*4882a593Smuzhiyun lst = lst->next;
172*4882a593Smuzhiyun X_PFX(list_free_1) (tem);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (data_ret != NULL)
176*4882a593Smuzhiyun *data_ret = data;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun return lst;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_filter)182*4882a593Smuzhiyun X_PFX(list_filter) (x_list * lst,
183*4882a593Smuzhiyun int (*pred)(void *item, void *data), void *data) {
184*4882a593Smuzhiyun x_list *ret = NULL, *node;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun for (node = lst; node != NULL; node = node->next) {
187*4882a593Smuzhiyun if ((*pred)(node->data, data))
188*4882a593Smuzhiyun ret = X_PFX(list_prepend) (ret, node->data);
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun return X_PFX(list_reverse) (ret);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_map)195*4882a593Smuzhiyun X_PFX(list_map) (x_list * lst,
196*4882a593Smuzhiyun void *(*fun)(void *item, void *data), void *data) {
197*4882a593Smuzhiyun x_list *ret = NULL, *node;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun for (node = lst; node != NULL; node = node->next) {
200*4882a593Smuzhiyun X_PFX(list_prepend) (ret, fun(node->data, data));
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun return X_PFX(list_reverse) (ret);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_copy)207*4882a593Smuzhiyun X_PFX(list_copy) (x_list * lst) {
208*4882a593Smuzhiyun x_list *copy = NULL;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun for (; lst != NULL; lst = lst->next) {
211*4882a593Smuzhiyun copy = X_PFX(list_prepend) (copy, lst->data);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun return X_PFX(list_reverse) (copy);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_remove)218*4882a593Smuzhiyun X_PFX(list_remove) (x_list * lst, void *data) {
219*4882a593Smuzhiyun x_list **ptr, *node;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun for (ptr = &lst; *ptr != NULL;) {
222*4882a593Smuzhiyun node = *ptr;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (node->data == data) {
225*4882a593Smuzhiyun *ptr = node->next;
226*4882a593Smuzhiyun X_PFX(list_free_1) (node);
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun else
229*4882a593Smuzhiyun ptr = &((*ptr)->next);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun return lst;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun X_EXTERN unsigned int
X_PFX(list_length)236*4882a593Smuzhiyun X_PFX(list_length) (x_list * lst) {
237*4882a593Smuzhiyun unsigned int n;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun n = 0;
240*4882a593Smuzhiyun for (; lst != NULL; lst = lst->next)
241*4882a593Smuzhiyun n++;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun return n;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun X_EXTERN void
X_PFX(list_foreach)247*4882a593Smuzhiyun X_PFX(list_foreach) (x_list * lst,
248*4882a593Smuzhiyun void (*fun)(void *data, void *user_data),
249*4882a593Smuzhiyun void *user_data) {
250*4882a593Smuzhiyun for (; lst != NULL; lst = lst->next) {
251*4882a593Smuzhiyun (*fun)(lst->data, user_data);
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun static x_list *
list_sort_1(x_list * lst,int length,int (* less)(const void *,const void *))256*4882a593Smuzhiyun list_sort_1(x_list *lst, int length,
257*4882a593Smuzhiyun int (*less)(const void *, const void *))
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun x_list *mid, *ptr;
260*4882a593Smuzhiyun x_list *out_head, *out;
261*4882a593Smuzhiyun int mid_point, i;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* This is a standard (stable) list merge sort */
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun if (length < 2)
266*4882a593Smuzhiyun return lst;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* Calculate the halfway point. Split the list into two sub-lists. */
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun mid_point = length / 2;
271*4882a593Smuzhiyun ptr = lst;
272*4882a593Smuzhiyun for (i = mid_point - 1; i > 0; i--)
273*4882a593Smuzhiyun ptr = ptr->next;
274*4882a593Smuzhiyun mid = ptr->next;
275*4882a593Smuzhiyun ptr->next = NULL;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* Sort each sub-list. */
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun lst = list_sort_1(lst, mid_point, less);
280*4882a593Smuzhiyun mid = list_sort_1(mid, length - mid_point, less);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* Then merge them back together. */
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun assert(lst != NULL && mid != NULL);
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if ((*less)(mid->data, lst->data))
287*4882a593Smuzhiyun out = out_head = mid, mid = mid->next;
288*4882a593Smuzhiyun else
289*4882a593Smuzhiyun out = out_head = lst, lst = lst->next;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun while (lst != NULL && mid != NULL)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun if ((*less)(mid->data, lst->data))
294*4882a593Smuzhiyun out = out->next = mid, mid = mid->next;
295*4882a593Smuzhiyun else
296*4882a593Smuzhiyun out = out->next = lst, lst = lst->next;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (lst != NULL)
300*4882a593Smuzhiyun out->next = lst;
301*4882a593Smuzhiyun else
302*4882a593Smuzhiyun out->next = mid;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun return out_head;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun X_EXTERN x_list *
X_PFX(list_sort)308*4882a593Smuzhiyun X_PFX(list_sort) (x_list * lst, int (*less)(const void *, const void *)) {
309*4882a593Smuzhiyun int length;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun length = X_PFX(list_length) (lst);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun return list_sort_1(lst, length, less);
314*4882a593Smuzhiyun }
315