static int spl_ptr_pqueue_zval_cmp(zval *a, zval *b, zval *object) { /* {{{ */ zval result; zval *a_priority_p = spl_pqueue_extract_helper(a, SPL_PQUEUE_EXTR_PRIORITY); zval *b_priority_p = spl_pqueue_extract_helper(b, SPL_PQUEUE_EXTR_PRIORITY); if ((!a_priority_p) || (!b_priority_p)) { zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); return 0; } if (EG(exception)) { return 0; } if (object) { spl_heap_object *heap_object = Z_SPLHEAP_P(object); if (heap_object->fptr_cmp) { zend_long lval = 0; if (spl_ptr_heap_cmp_cb_helper((zval *)object, heap_object, a_priority_p, b_priority_p, &lval) == FAILURE) { /* exception or call failure */ return 0; } return lval > 0 ? 1 : (lval < 0 ? -1 : 0); } } compare_function(&result, a_priority_p, b_priority_p); return (int)Z_LVAL(result); }
/* {{{ proto bool SplPriorityQueue::insert(mixed $value, mixed $priority) Push $value with the priority $priodiry on the priorityqueue */ SPL_METHOD(SplPriorityQueue, insert) { zval *data, *priority, elem; spl_heap_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &data, &priority) == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); if (intern->heap->flags & SPL_HEAP_CORRUPTED) { zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0); return; } if (Z_REFCOUNTED_P(data)) Z_ADDREF_P(data); if (Z_REFCOUNTED_P(priority)) Z_ADDREF_P(priority); array_init(&elem); add_assoc_zval_ex(&elem, "data", sizeof("data") - 1, data); add_assoc_zval_ex(&elem, "priority", sizeof("priority") - 1, priority); spl_ptr_heap_insert(intern->heap, &elem, getThis()); RETURN_TRUE; }
/* {{{ proto mixed SplPriorityQueue::top() Peek at the top element of the priority queue */ SPL_METHOD(SplPriorityQueue, top) { zval *value, *value_out; spl_heap_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); if (intern->heap->flags & SPL_HEAP_CORRUPTED) { zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0); return; } value = spl_ptr_heap_top(intern->heap); if (!value) { zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty heap", 0); return; } value_out = spl_pqueue_extract_helper(value, intern->flags); if (!value_out) { zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); return; } RETURN_ZVAL(value_out, 1, 0); }
/* {{{ proto mixed SplPriorityQueue::extract() extract the element out of the top of the priority queue */ SPL_METHOD(SplPriorityQueue, extract) { zval value, *value_out; spl_heap_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); if (intern->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(intern->heap, &value, getThis()); if (Z_ISUNDEF(value)) { zend_throw_exception(spl_ce_RuntimeException, "Can't extract from an empty heap", 0); return; } value_out = spl_pqueue_extract_helper(&value, intern->flags); if (!value_out) { zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); zval_ptr_dtor(&value); return; } ZVAL_DEREF(value_out); ZVAL_COPY(return_value, value_out); zval_ptr_dtor(&value); }
/* {{{ proto mixed SplHeap::extract() extract the element out of the top of the heap */ SPL_METHOD(SplHeap, extract) { zval value; spl_heap_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); if (intern->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(intern->heap, &value, getThis()); if (Z_ISUNDEF(value)) { zend_throw_exception(spl_ce_RuntimeException, "Can't extract from an empty heap", 0); return; } RETURN_ZVAL(&value, 1, 1); }
/* {{{ proto mixed SplHeap::top() Peek at the top element of the heap */ SPL_METHOD(SplHeap, top) { zval *value; spl_heap_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); if (intern->heap->flags & SPL_HEAP_CORRUPTED) { zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0); return; } value = spl_ptr_heap_top(intern->heap); if (!value) { zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty heap", 0); return; } RETURN_ZVAL(value, 1, 0); }
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_count = intern->heap->count; return std_object_handlers.get_properties(obj); }
/* {{{ proto int SplHeap::isEmpty() Return true if the heap is empty. */ SPL_METHOD(SplHeap, isEmpty) { spl_heap_object *intern = Z_SPLHEAP_P(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } RETURN_BOOL(spl_ptr_heap_count(intern->heap) == 0); }
/* {{{ proto int SplHeap::key() Return current array key */ SPL_METHOD(SplHeap, key) { spl_heap_object *intern = Z_SPLHEAP_P(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } RETURN_LONG(intern->heap->count - 1); }
/* {{{ proto bool SplHeap::valid() Check whether the datastructure contains more entries */ SPL_METHOD(SplHeap, valid) { spl_heap_object *intern = Z_SPLHEAP_P(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } RETURN_BOOL(intern->heap->count != 0); }
/* {{{ proto int SplHeap::isCorrupted() Tells if the heap is in a corrupted state*/ SPL_METHOD(SplHeap, isCorrupted) { spl_heap_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); RETURN_BOOL(intern->heap->flags & SPL_HEAP_CORRUPTED); }
/* {{{ proto void SplHeap::next() Move to next entry */ SPL_METHOD(SplHeap, next) { spl_heap_object *intern = Z_SPLHEAP_P(getThis()); zval elem; spl_ptr_heap_delete_top(intern->heap, &elem, getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } zval_ptr_dtor(&elem); }
/* {{{ proto int SplPriorityQueue::getExtractFlags() Get the flags of extraction*/ SPL_METHOD(SplPriorityQueue, getExtractFlags) { spl_heap_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); RETURN_LONG(intern->flags); }
/* {{{ proto int SplHeap::count() Return the number of elements in the heap. */ SPL_METHOD(SplHeap, count) { zend_long count; spl_heap_object *intern = Z_SPLHEAP_P(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } count = spl_ptr_heap_count(intern->heap); RETURN_LONG(count); }
/* {{{ proto int SplHeap::recoverFromCorruption() Recover from a corrupted state*/ SPL_METHOD(SplHeap, recoverFromCorruption) { spl_heap_object *intern; if (zend_parse_parameters_none() == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); intern->heap->flags = intern->heap->flags & ~SPL_HEAP_CORRUPTED; RETURN_TRUE; }
/* {{{ proto int SplPriorityQueue::setExtractFlags($flags) Set the flags of extraction*/ SPL_METHOD(SplPriorityQueue, setExtractFlags) { zend_long value; spl_heap_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); intern->flags = value & SPL_PQUEUE_EXTR_MASK; RETURN_LONG(intern->flags); }
/* {{{ proto mixed|NULL SplHeap::current() Return current datastructure entry */ SPL_METHOD(SplHeap, current) { spl_heap_object *intern = Z_SPLHEAP_P(getThis()); zval *element = &intern->heap->elements[0]; if (zend_parse_parameters_none() == FAILURE) { return; } if (!intern->heap->count || Z_ISUNDEF_P(element)) { RETURN_NULL(); } else { RETURN_ZVAL(element, 1, 0); } }
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); zval_ptr_dtor(&elem); zend_user_it_invalidate_current(iter); }
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)) { return NULL; } else { return element; } }
static HashTable* spl_heap_object_get_debug_info_helper(zend_class_entry *ce, zval *obj, int *is_temp) { /* {{{ */ spl_heap_object *intern = Z_SPLHEAP_P(obj); zval tmp, heap_array; zend_string *pnstr; int i; *is_temp = 0; if (!intern->std.properties) { rebuild_object_properties(&intern->std); } if (intern->debug_info == NULL) { ALLOC_HASHTABLE(intern->debug_info); ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0); } if (intern->debug_info->u.v.nApplyCount == 0) { zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref); pnstr = spl_gen_private_prop_name(ce, "flags", sizeof("flags")-1); ZVAL_LONG(&tmp, intern->flags); zend_hash_update(intern->debug_info, pnstr, &tmp); zend_string_release(pnstr); pnstr = spl_gen_private_prop_name(ce, "isCorrupted", sizeof("isCorrupted")-1); ZVAL_BOOL(&tmp, intern->heap->flags&SPL_HEAP_CORRUPTED); zend_hash_update(intern->debug_info, pnstr, &tmp); zend_string_release(pnstr); array_init(&heap_array); for (i = 0; i < intern->heap->count; ++i) { add_index_zval(&heap_array, i, &intern->heap->elements[i]); if (Z_REFCOUNTED(intern->heap->elements[i])) { Z_ADDREF(intern->heap->elements[i]); } } pnstr = spl_gen_private_prop_name(ce, "heap", sizeof("heap")-1); zend_hash_update(intern->debug_info, pnstr, &heap_array); zend_string_release(pnstr); } return intern->debug_info; }
static int spl_heap_object_count_elements(zval *object, zend_long *count) /* {{{ */ { spl_heap_object *intern = Z_SPLHEAP_P(object); if (intern->fptr_count) { zval rv; zend_call_method_with_0_params(object, intern->std.ce, &intern->fptr_count, "count", &rv); if (!Z_ISUNDEF(rv)) { *count = zval_get_long(&rv); zval_ptr_dtor(&rv); return SUCCESS; } *count = 0; return FAILURE; } *count = spl_ptr_heap_count(intern->heap); return SUCCESS; }
static zval *spl_pqueue_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)) { return NULL; } else { zval *data = spl_pqueue_extract_helper(element, object->flags); if (!data) { zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); } return data; } }
/* {{{ proto bool SplHeap::insert(mixed $value) Push $value on the heap */ SPL_METHOD(SplHeap, insert) { zval *value; spl_heap_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) { return; } intern = Z_SPLHEAP_P(getThis()); if (intern->heap->flags & SPL_HEAP_CORRUPTED) { zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0); return; } if (Z_REFCOUNTED_P(value)) Z_ADDREF_P(value); spl_ptr_heap_insert(intern->heap, value, getThis()); RETURN_TRUE; }
/* {{{ proto mixed|NULL SplPriorityQueue::current() Return current datastructure entry */ SPL_METHOD(SplPriorityQueue, current) { spl_heap_object *intern = Z_SPLHEAP_P(getThis()); zval *element = &intern->heap->elements[0]; if (zend_parse_parameters_none() == FAILURE) { return; } if (!intern->heap->count || Z_ISUNDEF_P(element)) { RETURN_NULL(); } else { zval *data = spl_pqueue_extract_helper(element, intern->flags); if (!data) { zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); RETURN_NULL(); } RETURN_ZVAL(data, 1, 0); } }
static int spl_heap_object_count_elements(zval *object, zend_long *count) /* {{{ */ { spl_heap_object *intern = Z_SPLHEAP_P(object); if (intern->fptr_count) { zval rv; zend_call_method_with_0_params(object, intern->std.ce, &intern->fptr_count, "count", &rv); if (!Z_ISUNDEF(rv)) { zval_ptr_dtor(&intern->retval); ZVAL_ZVAL(&intern->retval, &rv, 0, 0); convert_to_long(&intern->retval); *count = (zend_long) Z_LVAL(intern->retval); return SUCCESS; } *count = 0; return FAILURE; } *count = spl_ptr_heap_count(intern->heap); return SUCCESS; }
zend_object_iterator *spl_heap_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ { spl_heap_it *iterator; spl_heap_object *heap_object = Z_SPLHEAP_P(object); if (by_ref) { zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0); return NULL; } iterator = emalloc(sizeof(spl_heap_it)); zend_iterator_init(&iterator->intern.it); ZVAL_COPY(&iterator->intern.it.data, object); iterator->intern.it.funcs = &spl_heap_it_funcs; iterator->intern.ce = ce; iterator->flags = heap_object->flags; ZVAL_UNDEF(&iterator->intern.value); return &iterator->intern.it; }
static int spl_ptr_heap_zval_min_cmp(zval *a, zval *b, zval *object) { /* {{{ */ zval result; if (EG(exception)) { return 0; } if (object) { spl_heap_object *heap_object = Z_SPLHEAP_P(object); if (heap_object->fptr_cmp) { zend_long lval = 0; if (spl_ptr_heap_cmp_cb_helper(object, heap_object, a, b, &lval) == FAILURE) { /* exception or call failure */ return 0; } return lval > 0 ? 1 : (lval < 0 ? -1 : 0); } } compare_function(&result, b, a); return (int)Z_LVAL(result); }
static void spl_heap_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */ { spl_heap_object *object = Z_SPLHEAP_P(&iter->data); ZVAL_LONG(key, object->heap->count - 1); }
static zend_object *spl_heap_object_new_ex(zend_class_entry *class_type, zval *orig, int clone_orig) /* {{{ */ { spl_heap_object *intern; zend_class_entry *parent = class_type; int inherited = 0; intern = ecalloc(1, sizeof(spl_heap_object) + zend_object_properties_size(parent)); 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->ce_get_iterator = other->ce_get_iterator; if (clone_orig) { int i; intern->heap = spl_ptr_heap_clone(other->heap); for (i = 0; i < intern->heap->count; ++i) { if (Z_REFCOUNTED(intern->heap->elements[i])) { Z_ADDREF(intern->heap->elements[i]); } } } else { intern->heap = other->heap; } 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->std.handlers = &spl_handler_SplHeap; while (parent) { if (parent == spl_ce_SplPriorityQueue) { intern->heap->cmp = spl_ptr_pqueue_zval_cmp; intern->flags = SPL_PQUEUE_EXTR_DATA; intern->std.handlers = &spl_handler_SplPriorityQueue; 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) { break; } parent = parent->parent; inherited = 1; } if (!parent) { /* this must never happen */ php_error_docref(NULL, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplHeap"); } if (inherited) { intern->fptr_cmp = zend_hash_str_find_ptr(&class_type->function_table, "compare", sizeof("compare") - 1); if (intern->fptr_cmp->common.scope == parent) { intern->fptr_cmp = NULL; } intern->fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1); if (intern->fptr_count->common.scope == parent) { intern->fptr_count = NULL; } } return &intern->std; }
static int spl_heap_it_valid(zend_object_iterator *iter) /* {{{ */ { return ((Z_SPLHEAP_P(&iter->data))->heap->count != 0 ? SUCCESS : FAILURE); }