2 * Copyright © 2006 Keith Packard
3 * Copyright © 2006 Carl Worth
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
26 #include "cairo-skiplist-private.h"
29 #include <strings.h> /* ffs() */
32 #define ELT_DATA(elt) (void *) ((char*) (elt) - list->data_size)
33 #define NEXT_TO_ELT(next) (skip_elt_t *) ((char *) (next) - offsetof (skip_elt_t, next))
36 hars_petruska_f54_1_random (void)
38 # define rol(x,k) ((x << k) | (x >> (32-k)))
39 static uint32_t x
= 0;
40 x
= (x
^ rol(x
, 5) ^ rol(x
, 24)) + 0x37798849;
56 pool
= malloc (8192 - 8);
57 if (unlikely (pool
== NULL
))
61 pool
->rem
= 8192 - 8 - sizeof (struct pool
);
62 pool
->ptr
= (char *) (pool
+ 1);
68 pools_destroy (struct pool
*pool
)
70 while (pool
->next
!= NULL
) {
71 struct pool
*next
= pool
->next
;
78 * Initialize an empty skip list
81 _cairo_skip_list_init (cairo_skip_list_t
*list
,
82 cairo_skip_list_compare_t compare
,
87 list
->compare
= compare
;
88 list
->elt_size
= elt_size
;
89 list
->data_size
= elt_size
- sizeof (skip_elt_t
);
90 list
->pool
= (struct pool
*) list
->pool_embedded
;
91 list
->pool
->next
= NULL
;
92 list
->pool
->rem
= sizeof (list
->pool_embedded
) - sizeof (struct pool
);
93 list
->pool
->ptr
= list
->pool_embedded
+ sizeof (struct pool
);
95 for (i
= 0; i
< MAX_LEVEL
; i
++) {
96 list
->chains
[i
] = NULL
;
99 for (i
= 0; i
< MAX_FREELIST_LEVEL
; i
++) {
100 list
->freelists
[i
] = NULL
;
107 _cairo_skip_list_fini (cairo_skip_list_t
*list
)
109 pools_destroy (list
->pool
);
113 * Generate a random level number, distributed
114 * so that each level is 1/4 as likely as the one before
116 * Note that level numbers run 1 <= level < MAX_LEVEL
121 /* tricky bit -- each bit is '1' 75% of the time.
122 * This works because we only use the lower MAX_LEVEL
123 * bits, and MAX_LEVEL < 16 */
124 uint32_t bits
= hars_petruska_f54_1_random ();
126 return ffs (-(1<<MAX_LEVEL
) | bits
| bits
>> 16);
130 bits
|= -(1<<MAX_LEVEL
) | bits
>> 16;
131 while ((bits
& 1) == 0) {
140 pool_alloc (cairo_skip_list_t
*list
,
147 size
= list
->elt_size
+
148 (FREELIST_MAX_LEVEL_FOR (level
) - 1) * sizeof (skip_elt_t
*);
151 if (size
> pool
->rem
) {
153 if (unlikely (pool
== NULL
))
156 pool
->next
= list
->pool
;
168 alloc_node_for_level (cairo_skip_list_t
*list
, unsigned level
)
170 int freelist_level
= FREELIST_FOR_LEVEL (level
);
171 if (list
->freelists
[freelist_level
]) {
172 skip_elt_t
*elt
= list
->freelists
[freelist_level
];
173 list
->freelists
[freelist_level
] = elt
->prev
;
174 return ELT_DATA(elt
);
176 return pool_alloc (list
, level
);
180 free_elt (cairo_skip_list_t
*list
, skip_elt_t
*elt
)
182 int level
= elt
->prev_index
+ 1;
183 int freelist_level
= FREELIST_FOR_LEVEL (level
);
184 elt
->prev
= list
->freelists
[freelist_level
];
185 list
->freelists
[freelist_level
] = elt
;
189 * Insert 'data' into the list
192 _cairo_skip_list_insert (cairo_skip_list_t
*list
, void *data
, int unique
)
194 skip_elt_t
**update
[MAX_LEVEL
];
195 skip_elt_t
*prev
[MAX_LEVEL
];
197 skip_elt_t
*elt
, **next
;
198 int i
, level
, prev_index
;
201 * Find links along each chain
205 for (i
= list
->max_level
; --i
>= 0; )
209 for (; (elt
= next
[i
]); next
= elt
->next
)
211 int cmp
= list
->compare (list
, ELT_DATA(elt
), data
);
212 if (unique
&& 0 == cmp
)
213 return ELT_DATA(elt
);
219 if (next
!= list
->chains
)
220 prev
[i
] = NEXT_TO_ELT (next
);
224 level
= random_level ();
225 prev_index
= level
- 1;
228 * Create new list element
230 if (level
> list
->max_level
)
232 level
= list
->max_level
+ 1;
233 prev_index
= level
- 1;
234 prev
[prev_index
] = NULL
;
235 update
[list
->max_level
] = list
->chains
;
236 list
->max_level
= level
;
239 data_and_elt
= alloc_node_for_level (list
, level
);
240 if (unlikely (data_and_elt
== NULL
)) {
241 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
245 memcpy (data_and_elt
, data
, list
->data_size
);
246 elt
= (skip_elt_t
*) (data_and_elt
+ list
->data_size
);
248 elt
->prev_index
= prev_index
;
249 elt
->prev
= prev
[prev_index
];
252 * Insert into all chains
254 for (i
= 0; i
< level
; i
++)
256 elt
->next
[i
] = update
[i
][i
];
257 if (elt
->next
[i
] && elt
->next
[i
]->prev_index
== i
)
258 elt
->next
[i
]->prev
= elt
;
266 _cairo_skip_list_find (cairo_skip_list_t
*list
, void *data
)
269 skip_elt_t
**next
= list
->chains
;
273 * Walk chain pointers one level at a time
275 for (i
= list
->max_level
; --i
>= 0;)
276 while (next
[i
] && list
->compare (list
, data
, ELT_DATA(next
[i
])) > 0)
278 next
= next
[i
]->next
;
284 if (elt
&& list
->compare (list
, data
, ELT_DATA (elt
)) == 0)
285 return ELT_DATA (elt
);
291 _cairo_skip_list_delete (cairo_skip_list_t
*list
, void *data
)
293 skip_elt_t
**update
[MAX_LEVEL
], *prev
[MAX_LEVEL
];
294 skip_elt_t
*elt
, **next
;
298 * Find links along each chain
301 for (i
= list
->max_level
; --i
>= 0; )
303 for (; (elt
= next
[i
]); next
= elt
->next
)
305 if (list
->compare (list
, ELT_DATA (elt
), data
) >= 0)
308 update
[i
] = &next
[i
];
309 if (next
== list
->chains
)
312 prev
[i
] = NEXT_TO_ELT (next
);
315 assert (list
->compare (list
, ELT_DATA (elt
), data
) == 0);
316 for (i
= 0; i
< list
->max_level
&& *update
[i
] == elt
; i
++) {
317 *update
[i
] = elt
->next
[i
];
318 if (elt
->next
[i
] && elt
->next
[i
]->prev_index
== i
)
319 elt
->next
[i
]->prev
= prev
[i
];
321 while (list
->max_level
> 0 && list
->chains
[list
->max_level
- 1] == NULL
)
323 free_elt (list
, elt
);
327 _cairo_skip_list_delete_given (cairo_skip_list_t
*list
, skip_elt_t
*given
)
329 skip_elt_t
**update
[MAX_LEVEL
], *prev
[MAX_LEVEL
];
330 skip_elt_t
*elt
, **next
;
334 * Find links along each chain
337 next
= given
->prev
->next
;
340 for (i
= given
->prev_index
+ 1; --i
>= 0; )
342 for (; (elt
= next
[i
]); next
= elt
->next
)
347 update
[i
] = &next
[i
];
348 if (next
== list
->chains
)
351 prev
[i
] = NEXT_TO_ELT (next
);
354 assert (elt
== given
);
355 for (i
= 0; i
< (given
->prev_index
+ 1) && *update
[i
] == elt
; i
++) {
356 *update
[i
] = elt
->next
[i
];
357 if (elt
->next
[i
] && elt
->next
[i
]->prev_index
== i
)
358 elt
->next
[i
]->prev
= prev
[i
];
360 while (list
->max_level
> 0 && list
->chains
[list
->max_level
- 1] == NULL
)
362 free_elt (list
, elt
);
372 test_cmp (void *list
, void *A
, void *B
)
374 const test_elt_t
*a
= A
, *b
= B
;
381 cairo_skip_list_t list
;
385 _cairo_skip_list_init (&list
, test_cmp
, sizeof (test_elt_t
));
386 for (n
= 0; n
< 10000000; n
++) {
389 elt_and_data
= _cairo_skip_list_insert (&list
, &elt
, TRUE
);
390 assert (elt_and_data
!= NULL
);
392 _cairo_skip_list_fini (&list
);
397 /* required supporting stubs */
398 cairo_status_t
_cairo_error (cairo_status_t status
) { return status
; }