PHPAPI zend_class_entry *spl_ce_SplPriorityQueue;
-typedef void (*spl_ptr_heap_dtor_func)(zval *);
-typedef void (*spl_ptr_heap_ctor_func)(zval *);
-typedef int (*spl_ptr_heap_cmp_func)(zval *, zval *, zval *);
+typedef void (*spl_ptr_heap_dtor_func)(void *);
+typedef void (*spl_ptr_heap_ctor_func)(void *);
+typedef int (*spl_ptr_heap_cmp_func)(void *, void *, zval *);
typedef struct _spl_ptr_heap {
- zval *elements;
+ void *elements;
spl_ptr_heap_ctor_func ctor;
spl_ptr_heap_dtor_func dtor;
spl_ptr_heap_cmp_func cmp;
int count;
- int max_size;
int flags;
+ size_t max_size;
+ size_t elem_size;
} spl_ptr_heap;
typedef struct _spl_heap_object spl_heap_object;
#define Z_SPLHEAP_P(zv) spl_heap_from_obj(Z_OBJ_P((zv)))
-static void spl_ptr_heap_zval_dtor(zval *elem) { /* {{{ */
- if (!Z_ISUNDEF_P(elem)) {
- zval_ptr_dtor(elem);
- }
+static zend_always_inline void *spl_heap_elem(spl_ptr_heap *heap, size_t i) {
+ return (void *) ((char *) heap->elements + heap->elem_size * i);
+}
+
+static zend_always_inline void spl_heap_elem_copy(spl_ptr_heap *heap, void *to, void *from) {
+ memcpy(to, from, heap->elem_size);
+}
+
+static void spl_ptr_heap_zval_dtor(void *elem) { /* {{{ */
+ zval_ptr_dtor((zval *) elem);
}
/* }}} */
-static void spl_ptr_heap_zval_ctor(zval *elem) { /* {{{ */
- Z_TRY_ADDREF_P(elem);
+static void spl_ptr_heap_zval_ctor(void *elem) { /* {{{ */
+ Z_TRY_ADDREF_P((zval *) elem);
}
/* }}} */
-static void spl_ptr_heap_pqueue_elem_dtor(zval *zv) { /* {{{ */
- if (!Z_ISUNDEF_P(zv)) {
- spl_pqueue_elem *elem = Z_PTR_P(zv);
- zval_ptr_dtor(&elem->data);
- zval_ptr_dtor(&elem->priority);
- efree(elem);
- }
+static void spl_ptr_heap_pqueue_elem_dtor(void *elem) { /* {{{ */
+ spl_pqueue_elem *pq_elem = elem;
+ zval_ptr_dtor(&pq_elem->data);
+ zval_ptr_dtor(&pq_elem->priority);
}
/* }}} */
-static void spl_ptr_heap_pqueue_elem_ctor(zval *zv) { /* {{{ */
- spl_pqueue_elem *old_elem = Z_PTR_P(zv);
- spl_pqueue_elem *new_elem = emalloc(sizeof(spl_pqueue_elem));
- ZVAL_COPY(&new_elem->data, &old_elem->data);
- ZVAL_COPY(&new_elem->priority, &old_elem->priority);
- Z_PTR_P(zv) = new_elem;
+static void spl_ptr_heap_pqueue_elem_ctor(void *elem) { /* {{{ */
+ spl_pqueue_elem *pq_elem = elem;
+ Z_TRY_ADDREF_P(&pq_elem->data);
+ Z_TRY_ADDREF_P(&pq_elem->priority);
}
/* }}} */
}
/* }}} */
-static void spl_pqueue_extract_helper(zval *result, zval *value, int flags) /* {{{ */
+static void spl_pqueue_extract_helper(zval *result, spl_pqueue_elem *elem, int flags) /* {{{ */
{
- spl_pqueue_elem *elem = Z_PTR_P(value);
if ((flags & SPL_PQUEUE_EXTR_BOTH) == SPL_PQUEUE_EXTR_BOTH) {
array_init(result);
Z_TRY_ADDREF(elem->data);
}
/* }}} */
-static int spl_ptr_heap_zval_max_cmp(zval *a, zval *b, zval *object) { /* {{{ */
+static int spl_ptr_heap_zval_max_cmp(void *x, void *y, zval *object) { /* {{{ */
+ zval *a = x, *b = y;
zval result;
if (EG(exception)) {
}
/* }}} */
-static int spl_ptr_heap_zval_min_cmp(zval *a, zval *b, zval *object) { /* {{{ */
+static int spl_ptr_heap_zval_min_cmp(void *x, void *y, zval *object) { /* {{{ */
+ zval *a = x, *b = y;
zval result;
if (EG(exception)) {
}
/* }}} */
-static int spl_ptr_pqueue_elem_cmp(zval *a_zv, zval *b_zv, zval *object) { /* {{{ */
- spl_pqueue_elem *a = Z_PTR_P(a_zv);
- spl_pqueue_elem *b = Z_PTR_P(b_zv);
+static int spl_ptr_pqueue_elem_cmp(void *x, void *y, zval *object) { /* {{{ */
+ spl_pqueue_elem *a = x;
+ spl_pqueue_elem *b = y;
zval *a_priority_p = &a->priority;
zval *b_priority_p = &b->priority;
zval result;
}
/* }}} */
-static spl_ptr_heap *spl_ptr_heap_init(spl_ptr_heap_cmp_func cmp, spl_ptr_heap_ctor_func ctor, spl_ptr_heap_dtor_func dtor) /* {{{ */
+static spl_ptr_heap *spl_ptr_heap_init(spl_ptr_heap_cmp_func cmp, spl_ptr_heap_ctor_func ctor, spl_ptr_heap_dtor_func dtor, size_t elem_size) /* {{{ */
{
spl_ptr_heap *heap = emalloc(sizeof(spl_ptr_heap));
heap->dtor = dtor;
heap->ctor = ctor;
heap->cmp = cmp;
- heap->elements = ecalloc(PTR_HEAP_BLOCK_SIZE, sizeof(zval));
+ heap->elements = ecalloc(PTR_HEAP_BLOCK_SIZE, elem_size);
heap->max_size = PTR_HEAP_BLOCK_SIZE;
heap->count = 0;
heap->flags = 0;
+ heap->elem_size = elem_size;
return heap;
}
/* }}} */
-static void spl_ptr_heap_insert(spl_ptr_heap *heap, zval *elem, void *cmp_userdata) { /* {{{ */
+static void spl_ptr_heap_insert(spl_ptr_heap *heap, void *elem, void *cmp_userdata) { /* {{{ */
int i;
if (heap->count+1 > heap->max_size) {
+ size_t alloc_size = heap->max_size * heap->elem_size;
/* we need to allocate more memory */
- heap->elements = erealloc(heap->elements, heap->max_size * 2 * sizeof(zval));
- memset(heap->elements + heap->max_size, 0, heap->max_size * sizeof(zval));
+ heap->elements = erealloc(heap->elements, 2 * alloc_size);
+ memset((char *) heap->elements + alloc_size, 0, alloc_size);
heap->max_size *= 2;
}
/* sifting up */
- for (i = heap->count; i > 0 && heap->cmp(&heap->elements[(i-1)/2], elem, cmp_userdata) < 0; i = (i-1)/2) {
- heap->elements[i] = heap->elements[(i-1)/2];
+ for (i = heap->count; i > 0 && heap->cmp(spl_heap_elem(heap, (i-1)/2), elem, cmp_userdata) < 0; i = (i-1)/2) {
+ spl_heap_elem_copy(heap, spl_heap_elem(heap, i), spl_heap_elem(heap, (i-1)/2));
}
heap->count++;
heap->flags |= SPL_HEAP_CORRUPTED;
}
- ZVAL_COPY_VALUE(&heap->elements[i], elem);
+ spl_heap_elem_copy(heap, spl_heap_elem(heap, i), elem);
}
/* }}} */
-static zval *spl_ptr_heap_top(spl_ptr_heap *heap) { /* {{{ */
+static void *spl_ptr_heap_top(spl_ptr_heap *heap) { /* {{{ */
if (heap->count == 0) {
return NULL;
}
- return Z_ISUNDEF(heap->elements[0])? NULL : &heap->elements[0];
+ return heap->elements;
}
/* }}} */
-static void spl_ptr_heap_delete_top(spl_ptr_heap *heap, zval *elem, void *cmp_userdata) { /* {{{ */
+static int spl_ptr_heap_delete_top(spl_ptr_heap *heap, void *elem, void *cmp_userdata) { /* {{{ */
int i, j;
const int limit = (heap->count-1)/2;
- zval *bottom;
+ void *bottom;
if (heap->count == 0) {
- ZVAL_UNDEF(elem);
- return;
+ return FAILURE;
+ }
+
+ if (elem) {
+ spl_heap_elem_copy(heap, elem, spl_heap_elem(heap, 0));
+ } else {
+ heap->dtor(spl_heap_elem(heap, 0));
}
- ZVAL_COPY_VALUE(elem, &heap->elements[0]);
- bottom = &heap->elements[--heap->count];
+ bottom = spl_heap_elem(heap, --heap->count);
for (i = 0; i < limit; i = j) {
/* Find smaller child */
j = i * 2 + 1;
- if(j != heap->count && heap->cmp(&heap->elements[j+1], &heap->elements[j], cmp_userdata) > 0) {
+ if (j != heap->count && heap->cmp(spl_heap_elem(heap, j+1), spl_heap_elem(heap, j), cmp_userdata) > 0) {
j++; /* next child is bigger */
}
/* swap elements between two levels */
- if(heap->cmp(bottom, &heap->elements[j], cmp_userdata) < 0) {
- heap->elements[i] = heap->elements[j];
+ if(heap->cmp(bottom, spl_heap_elem(heap, j), cmp_userdata) < 0) {
+ spl_heap_elem_copy(heap, spl_heap_elem(heap, i), spl_heap_elem(heap, j));
} else {
break;
}
heap->flags |= SPL_HEAP_CORRUPTED;
}
- ZVAL_COPY_VALUE(&heap->elements[i], bottom);
+ spl_heap_elem_copy(heap, spl_heap_elem(heap, i), bottom);
+ return SUCCESS;
}
/* }}} */
heap->max_size = from->max_size;
heap->count = from->count;
heap->flags = from->flags;
+ heap->elem_size = from->elem_size;
- heap->elements = safe_emalloc(sizeof(zval), from->max_size, 0);
- memcpy(heap->elements, from->elements, sizeof(zval)*from->max_size);
+ heap->elements = safe_emalloc(from->elem_size, from->max_size, 0);
+ memcpy(heap->elements, from->elements, from->elem_size * from->max_size);
- for (i=0; i < heap->count; ++i) {
- heap->ctor(&heap->elements[i]);
+ for (i = 0; i < heap->count; ++i) {
+ heap->ctor(spl_heap_elem(heap, i));
}
return heap;
static void spl_ptr_heap_destroy(spl_ptr_heap *heap) { /* {{{ */
int i;
- for (i=0; i < heap->count; ++i) {
- heap->dtor(&heap->elements[i]);
+ for (i = 0; i < heap->count; ++i) {
+ heap->dtor(spl_heap_elem(heap, i));
}
efree(heap->elements);
zend_object_std_init(&intern->std, class_type);
object_properties_init(&intern->std, class_type);
- intern->flags = 0;
- intern->fptr_cmp = NULL;
-
if (orig) {
spl_heap_object *other = Z_SPLHEAP_P(orig);
+ intern->std.handlers = other->std.handlers;
intern->ce_get_iterator = other->ce_get_iterator;
if (clone_orig) {
}
intern->flags = other->flags;
- } else {
- intern->heap = spl_ptr_heap_init(spl_ptr_heap_zval_max_cmp, spl_ptr_heap_zval_ctor, spl_ptr_heap_zval_dtor);
+ intern->fptr_cmp = other->fptr_cmp;
+ intern->fptr_count = other->fptr_count;
+ return &intern->std;
}
- intern->std.handlers = &spl_handler_SplHeap;
-
while (parent) {
if (parent == spl_ce_SplPriorityQueue) {
- intern->heap->cmp = spl_ptr_pqueue_elem_cmp;
- intern->heap->ctor = spl_ptr_heap_pqueue_elem_ctor;
- intern->heap->dtor = spl_ptr_heap_pqueue_elem_dtor;
- intern->flags = SPL_PQUEUE_EXTR_DATA;
+ intern->heap = spl_ptr_heap_init(spl_ptr_pqueue_elem_cmp, spl_ptr_heap_pqueue_elem_ctor, spl_ptr_heap_pqueue_elem_dtor, sizeof(spl_pqueue_elem));
intern->std.handlers = &spl_handler_SplPriorityQueue;
+ intern->flags = SPL_PQUEUE_EXTR_DATA;
break;
}
- if (parent == spl_ce_SplMinHeap) {
- intern->heap->cmp = spl_ptr_heap_zval_min_cmp;
- break;
- }
-
- if (parent == spl_ce_SplMaxHeap) {
- intern->heap->cmp = spl_ptr_heap_zval_max_cmp;
- break;
- }
-
- if (parent == spl_ce_SplHeap) {
+ if (parent == spl_ce_SplMinHeap || parent == spl_ce_SplMaxHeap
+ || parent == spl_ce_SplHeap) {
+ intern->heap = spl_ptr_heap_init(
+ parent == spl_ce_SplMinHeap ? spl_ptr_heap_zval_min_cmp : spl_ptr_heap_zval_max_cmp,
+ spl_ptr_heap_zval_ctor, spl_ptr_heap_zval_dtor, sizeof(zval));
+ intern->std.handlers = &spl_handler_SplHeap;
break;
}
for (i = 0; i < intern->heap->count; ++i) {
if (ce == spl_ce_SplPriorityQueue) {
+ spl_pqueue_elem *pq_elem = spl_heap_elem(intern->heap, i);
zval elem;
- spl_pqueue_extract_helper(&elem, &intern->heap->elements[i], SPL_PQUEUE_EXTR_BOTH);
+ spl_pqueue_extract_helper(&elem, pq_elem, SPL_PQUEUE_EXTR_BOTH);
add_index_zval(&heap_array, i, &elem);
} else {
- add_index_zval(&heap_array, i, &intern->heap->elements[i]);
- Z_TRY_ADDREF(intern->heap->elements[i]);
+ zval *elem = spl_heap_elem(intern->heap, i);
+ add_index_zval(&heap_array, i, elem);
+ Z_TRY_ADDREF_P(elem);
}
}
static HashTable *spl_heap_object_get_gc(zval *obj, zval **gc_data, int *gc_data_count) /* {{{ */
{
spl_heap_object *intern = Z_SPLHEAP_P(obj);
- *gc_data = intern->heap->elements;
+ *gc_data = (zval *) intern->heap->elements;
*gc_data_count = intern->heap->count;
return zend_std_get_properties(obj);
}
/* }}} */
+static HashTable *spl_pqueue_object_get_gc(zval *obj, zval **gc_data, int *gc_data_count) /* {{{ */
+{
+ spl_heap_object *intern = Z_SPLHEAP_P(obj);
+ *gc_data = (zval *) intern->heap->elements;
+ /* Two zvals (value and priority) per pqueue entry */
+ *gc_data_count = 2 * intern->heap->count;
+
+ return zend_std_get_properties(obj);
+}
+/* }}} */
+
static HashTable* spl_heap_object_get_debug_info(zval *obj, int *is_temp) /* {{{ */
{
return spl_heap_object_get_debug_info_helper(spl_ce_SplHeap, obj, is_temp);
return;
}
- spl_ptr_heap_delete_top(intern->heap, return_value, ZEND_THIS);
-
- if (Z_ISUNDEF_P(return_value)) {
+ if (spl_ptr_heap_delete_top(intern->heap, return_value, ZEND_THIS) == FAILURE) {
zend_throw_exception(spl_ce_RuntimeException, "Can't extract from an empty heap", 0);
return;
}
Push $value with the priority $priodiry on the priorityqueue */
SPL_METHOD(SplPriorityQueue, insert)
{
- zval *data, *priority, elem_zv;
+ zval *data, *priority;
spl_heap_object *intern;
- spl_pqueue_elem *elem;
+ spl_pqueue_elem elem;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &data, &priority) == FAILURE) {
return;
return;
}
- elem = emalloc(sizeof(spl_pqueue_elem));
- ZVAL_COPY(&elem->data, data);
- ZVAL_COPY(&elem->priority, priority);
- ZVAL_PTR(&elem_zv, elem);
+ ZVAL_COPY(&elem.data, data);
+ ZVAL_COPY(&elem.priority, priority);
- spl_ptr_heap_insert(intern->heap, &elem_zv, ZEND_THIS);
+ spl_ptr_heap_insert(intern->heap, &elem, ZEND_THIS);
RETURN_TRUE;
}
extract the element out of the top of the priority queue */
SPL_METHOD(SplPriorityQueue, extract)
{
- zval value;
+ spl_pqueue_elem elem;
spl_heap_object *intern;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
- spl_ptr_heap_delete_top(intern->heap, &value, ZEND_THIS);
-
- if (Z_ISUNDEF(value)) {
+ if (spl_ptr_heap_delete_top(intern->heap, &elem, ZEND_THIS) == FAILURE) {
zend_throw_exception(spl_ce_RuntimeException, "Can't extract from an empty heap", 0);
return;
}
- spl_pqueue_extract_helper(return_value, &value, intern->flags);
- spl_ptr_heap_pqueue_elem_dtor(&value);
+ spl_pqueue_extract_helper(return_value, &elem, intern->flags);
+ spl_ptr_heap_pqueue_elem_dtor(&elem);
}
/* }}} */
Peek at the top element of the priority queue */
SPL_METHOD(SplPriorityQueue, top)
{
- zval *value;
spl_heap_object *intern;
+ spl_pqueue_elem *elem;
if (zend_parse_parameters_none() == FAILURE) {
return;
return;
}
- value = spl_ptr_heap_top(intern->heap);
+ elem = spl_ptr_heap_top(intern->heap);
- if (!value) {
+ if (!elem) {
zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty heap", 0);
return;
}
- spl_pqueue_extract_helper(return_value, value, intern->flags);
+ spl_pqueue_extract_helper(return_value, elem, intern->flags);
}
/* }}} */
static zval *spl_heap_it_get_current_data(zend_object_iterator *iter) /* {{{ */
{
spl_heap_object *object = Z_SPLHEAP_P(&iter->data);
- zval *element = &object->heap->elements[0];
if (object->heap->flags & SPL_HEAP_CORRUPTED) {
zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0);
return NULL;
}
- if (object->heap->count == 0 || Z_ISUNDEF_P(element)) {
+ if (object->heap->count == 0) {
return NULL;
} else {
- return element;
+ return spl_heap_elem(object->heap, 0);
}
}
/* }}} */
{
zend_user_iterator *user_it = (zend_user_iterator *) iter;
spl_heap_object *object = Z_SPLHEAP_P(&iter->data);
- zval *element = &object->heap->elements[0];
if (object->heap->flags & SPL_HEAP_CORRUPTED) {
zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0);
return NULL;
}
- if (object->heap->count == 0 || Z_ISUNDEF_P(element)) {
+ if (object->heap->count == 0) {
return NULL;
}
+
if (Z_ISUNDEF(user_it->value)) {
- spl_pqueue_extract_helper(&user_it->value, element, object->flags);
+ spl_pqueue_elem *elem = spl_heap_elem(object->heap, 0);
+ spl_pqueue_extract_helper(&user_it->value, elem, object->flags);
}
return &user_it->value;
}
static void spl_heap_it_move_forward(zend_object_iterator *iter) /* {{{ */
{
spl_heap_object *object = Z_SPLHEAP_P(&iter->data);
- zval elem;
if (object->heap->flags & SPL_HEAP_CORRUPTED) {
zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0);
return;
}
- spl_ptr_heap_delete_top(object->heap, &elem, &iter->data);
- object->heap->dtor(&elem);
-
+ spl_ptr_heap_delete_top(object->heap, NULL, &iter->data);
zend_user_it_invalidate_current(iter);
}
/* }}} */
SPL_METHOD(SplHeap, next)
{
spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS);
- zval elem;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
- spl_ptr_heap_delete_top(intern->heap, &elem, ZEND_THIS);
- intern->heap->dtor(&elem);
+ spl_ptr_heap_delete_top(intern->heap, NULL, ZEND_THIS);
}
/* }}} */
SPL_METHOD(SplHeap, current)
{
spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS);
- zval *element = &intern->heap->elements[0];
if (zend_parse_parameters_none() == FAILURE) {
return;
}
- if (!intern->heap->count || Z_ISUNDEF_P(element)) {
+ if (!intern->heap->count) {
RETURN_NULL();
} else {
+ zval *element = spl_heap_elem(intern->heap, 0);
ZVAL_COPY_DEREF(return_value, element);
}
}
SPL_METHOD(SplPriorityQueue, current)
{
spl_heap_object *intern = Z_SPLHEAP_P(ZEND_THIS);
- zval *element = &intern->heap->elements[0];
if (zend_parse_parameters_none() == FAILURE) {
return;
}
- if (!intern->heap->count || Z_ISUNDEF_P(element)) {
+ if (!intern->heap->count) {
RETURN_NULL();
} else {
- spl_pqueue_extract_helper(return_value, element, intern->flags);
+ spl_pqueue_elem *elem = spl_heap_elem(intern->heap, 0);
+ spl_pqueue_extract_helper(return_value, elem, intern->flags);
}
}
/* }}} */
spl_handler_SplPriorityQueue.clone_obj = spl_heap_object_clone;
spl_handler_SplPriorityQueue.count_elements = spl_heap_object_count_elements;
spl_handler_SplPriorityQueue.get_debug_info = spl_pqueue_object_get_debug_info;
- spl_handler_SplPriorityQueue.get_gc = spl_heap_object_get_gc;
+ spl_handler_SplPriorityQueue.get_gc = spl_pqueue_object_get_gc;
spl_handler_SplPriorityQueue.dtor_obj = zend_objects_destroy_object;
spl_handler_SplPriorityQueue.free_obj = spl_heap_object_free_storage;