[skiplist] Allocate elements in chunks.

Use a pool allocator to preallocate a chunk from which to allocate the
skiplist elements (if we failed to reallocate from the freelists).
This commit is contained in:
Chris Wilson 2008-11-26 12:33:12 +00:00
parent 903b39c304
commit 2b7c6f361a
3 changed files with 94 additions and 27 deletions

View file

@ -966,10 +966,13 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue,
int i;
cairo_bo_event_t *events, **sorted_event_ptrs;
unsigned num_events = 2*num_edges;
cairo_status_t status;
_cairo_skip_list_init (&event_queue->intersection_queue,
cairo_bo_event_compare_abstract,
sizeof (cairo_bo_event_t));
status = _cairo_skip_list_init (&event_queue->intersection_queue,
cairo_bo_event_compare_abstract,
sizeof (cairo_bo_event_t));
if (unlikely (status))
return status;
/* The skip_elt_t field of a cairo_bo_event_t isn't used for start
* or stop events, so this allocation is safe. XXX: make the
@ -1053,15 +1056,22 @@ _cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_
return _cairo_bo_event_queue_insert (event_queue, &event);
}
static void
static cairo_status_t
_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line)
{
_cairo_skip_list_init (&sweep_line->active_edges,
_sweep_line_elt_compare,
sizeof (sweep_line_elt_t));
cairo_status_t status;
status = _cairo_skip_list_init (&sweep_line->active_edges,
_sweep_line_elt_compare,
sizeof (sweep_line_elt_t));
if (unlikely (status))
return status;
sweep_line->head = NULL;
sweep_line->tail = NULL;
sweep_line->current_y = 0;
return CAIRO_STATUS_SUCCESS;
}
static void
@ -1110,7 +1120,8 @@ _cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
{
cairo_bo_edge_t **left_next, **right_prev;
_cairo_skip_list_delete_given (&sweep_line->active_edges, &edge->sweep_line_elt->elt);
_cairo_skip_list_delete_given (&sweep_line->active_edges,
&edge->sweep_line_elt->elt);
left_next = &sweep_line->head;
if (edge->prev)
@ -1495,7 +1506,10 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t *edges,
if (status)
return status;
_cairo_bo_sweep_line_init (&sweep_line);
status = _cairo_bo_sweep_line_init (&sweep_line);
if (unlikely (status))
goto CLEANUP_EVENT_QUEUE;
_cairo_bo_traps_init (&bo_traps, traps, xmin, ymin, xmax, ymax);
#if DEBUG_PRINT_STATE
@ -1621,6 +1635,7 @@ _cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_edge_t *edges,
}
_cairo_bo_traps_fini (&bo_traps);
_cairo_bo_sweep_line_fini (&sweep_line);
CLEANUP_EVENT_QUEUE:
_cairo_bo_event_queue_fini (&event_queue);
return status;
}

View file

@ -70,6 +70,7 @@ typedef struct _skip_list {
size_t data_size;
skip_elt_t *chains[MAX_LEVEL];
skip_elt_t *freelists[MAX_FREELIST_LEVEL];
struct pool *pool;
int max_level;
} cairo_skip_list_t;
@ -81,7 +82,7 @@ typedef struct _skip_list {
* sizeof) is passed for elt_size. Note that the structure used for
* list elements must have as its final member a skip_elt_t
*/
cairo_private void
cairo_private cairo_status_t
_cairo_skip_list_init (cairo_skip_list_t *list,
cairo_skip_list_compare_t compare,
size_t elt_size);

View file

@ -38,10 +38,42 @@ hars_petruska_f54_1_random (void)
# undef rol
}
struct pool {
struct pool *next;
char *ptr;
unsigned int rem;
};
static struct pool *
pool_new (void)
{
struct pool *pool;
pool = malloc (8192 - 8);
if (unlikely (pool == NULL))
return NULL;
pool->next = NULL;
pool->rem = 8192 - 8 - sizeof (struct pool);
pool->ptr = (char *) (pool + 1);
return pool;
}
static void
pools_destroy (struct pool *pool)
{
while (pool != NULL) {
struct pool *next = pool->next;
free (pool);
pool = next;
}
}
/*
* Initialize an empty skip list
*/
void
cairo_status_t
_cairo_skip_list_init (cairo_skip_list_t *list,
cairo_skip_list_compare_t compare,
size_t elt_size)
@ -51,6 +83,9 @@ _cairo_skip_list_init (cairo_skip_list_t *list,
list->compare = compare;
list->elt_size = elt_size;
list->data_size = elt_size - sizeof (skip_elt_t);
list->pool = pool_new ();
if (unlikely (list->pool == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < MAX_LEVEL; i++) {
list->chains[i] = NULL;
@ -61,25 +96,14 @@ _cairo_skip_list_init (cairo_skip_list_t *list,
}
list->max_level = 0;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_skip_list_fini (cairo_skip_list_t *list)
{
skip_elt_t *elt;
int i;
while ((elt = list->chains[0])) {
_cairo_skip_list_delete_given (list, elt);
}
for (i=0; i<MAX_FREELIST_LEVEL; i++) {
elt = list->freelists[i];
while (elt) {
skip_elt_t *nextfree = elt->prev;
free (ELT_DATA(elt));
elt = nextfree;
}
}
pools_destroy (list->pool);
}
/*
@ -109,6 +133,34 @@ random_level (void)
#endif
}
static void *
pool_alloc (cairo_skip_list_t *list,
unsigned int level)
{
unsigned int size;
struct pool *pool;
void *ptr;
size = list->elt_size +
(FREELIST_MAX_LEVEL_FOR (level) - 1) * sizeof (skip_elt_t *);
pool = list->pool;
if (size > pool->rem) {
pool = pool_new ();
if (unlikely (pool == NULL))
return NULL;
pool->next = list->pool;
list->pool = pool;
}
ptr = pool->ptr;
pool->ptr += size;
pool->rem -= size;
return ptr;
}
static void *
alloc_node_for_level (cairo_skip_list_t *list, unsigned level)
{
@ -118,8 +170,7 @@ alloc_node_for_level (cairo_skip_list_t *list, unsigned level)
list->freelists[freelist_level] = elt->prev;
return ELT_DATA(elt);
}
return malloc (list->elt_size
+ (FREELIST_MAX_LEVEL_FOR (level) - 1) * sizeof (skip_elt_t *));
return pool_alloc (list, level);
}
static void