diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c index cd150218e..c115419a9 100644 --- a/src/cairo-bentley-ottmann.c +++ b/src/cairo-bentley-ottmann.c @@ -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; } diff --git a/src/cairo-skiplist-private.h b/src/cairo-skiplist-private.h index 3a948afce..8c7dc9773 100644 --- a/src/cairo-skiplist-private.h +++ b/src/cairo-skiplist-private.h @@ -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); diff --git a/src/cairo-skiplist.c b/src/cairo-skiplist.c index d03a6bfcb..5fe2bd0cd 100644 --- a/src/cairo-skiplist.c +++ b/src/cairo-skiplist.c @@ -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; ifreelists[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