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