/* {{{ proto void SplDoublyLinkedList::__unserialize(array serialized) */ SPL_METHOD(SplDoublyLinkedList, __unserialize) { spl_dllist_object *intern = Z_SPLDLLIST_P(ZEND_THIS); HashTable *data; zval *flags_zv, *storage_zv, *members_zv, *elem; if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { return; } flags_zv = zend_hash_index_find(data, 0); storage_zv = zend_hash_index_find(data, 1); members_zv = zend_hash_index_find(data, 2); if (!flags_zv || !storage_zv || !members_zv || Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(storage_zv) != IS_ARRAY || Z_TYPE_P(members_zv) != IS_ARRAY) { zend_throw_exception(spl_ce_UnexpectedValueException, "Incomplete or ill-typed serialization data", 0); return; } intern->flags = (int) Z_LVAL_P(flags_zv); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(storage_zv), elem) { spl_ptr_llist_push(intern->llist, elem); } ZEND_HASH_FOREACH_END();
/* {{{ proto void SplDoublyLinkedList::unserialize(string serialized) Unserializes storage */ SPL_METHOD(SplDoublyLinkedList, unserialize) { spl_dllist_object *intern = Z_SPLDLLIST_P(getThis()); zval flags, elem; char *buf; size_t buf_len; const unsigned char *p, *s; php_unserialize_data_t var_hash; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) { return; } if (buf_len == 0) { return; } s = p = (const unsigned char*)buf; PHP_VAR_UNSERIALIZE_INIT(var_hash); /* flags */ if (!php_var_unserialize(&flags, &p, s + buf_len, &var_hash)) { goto error; } if (Z_TYPE(flags) != IS_LONG) { zval_ptr_dtor(&flags); goto error; } intern->flags = (int)Z_LVAL(flags); zval_ptr_dtor(&flags); /* elements */ while(*p == ':') { ++p; if (!php_var_unserialize(&elem, &p, s + buf_len, &var_hash)) { goto error; } spl_ptr_llist_push(intern->llist, &elem); zval_ptr_dtor(&elem); } if (*p != '\0') { goto error; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return; error: PHP_VAR_UNSERIALIZE_DESTROY(var_hash); zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Error at offset %pd of %d bytes", (zend_long)((char*)p - buf), buf_len); return; } /* }}} */
/* {{{ proto void SplDoublyLinkedList::add(mixed $index, mixed $newval) Inserts a new entry before the specified $index consisting of $newval. */ SPL_METHOD(SplDoublyLinkedList, add) { zval *zindex, *value; spl_dllist_object *intern; spl_ptr_llist_element *element; zend_long index; if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zindex, &value) == FAILURE) { return; } intern = Z_SPLDLLIST_P(getThis()); index = spl_offset_convert_to_long(zindex); if (index < 0 || index > intern->llist->count) { zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0); return; } if (Z_REFCOUNTED_P(value)) { Z_ADDREF_P(value); } if (index == intern->llist->count) { /* If index is the last entry+1 then we do a push because we're not inserting before any entry */ spl_ptr_llist_push(intern->llist, value); } else { /* Create the new element we want to insert */ spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element)); /* Get the element we want to insert before */ element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); ZVAL_COPY_VALUE(&elem->data, value); elem->rc = 1; /* connect to the neighbours */ elem->next = element; elem->prev = element->prev; /* connect the neighbours to this new element */ if (elem->prev == NULL) { intern->llist->head = elem; } else { element->prev->next = elem; } element->prev = elem; intern->llist->count++; if (intern->llist->ctor) { intern->llist->ctor(elem); } } } /* }}} */
/* {{{ proto void SplDoublyLinkedList::offsetSet(mixed $index, mixed $newval) Sets the value at the specified $index to $newval. */ SPL_METHOD(SplDoublyLinkedList, offsetSet) { zval *zindex, *value; spl_dllist_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zindex, &value) == FAILURE) { return; } intern = Z_SPLDLLIST_P(getThis()); if (Z_TYPE_P(zindex) == IS_NULL) { /* $obj[] = ... */ spl_ptr_llist_push(intern->llist, value); } else { /* $obj[$foo] = ... */ zend_long index; spl_ptr_llist_element *element; index = spl_offset_convert_to_long(zindex); if (index < 0 || index >= intern->llist->count) { zval_ptr_dtor(value); zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0); return; } element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); if (element != NULL) { /* call dtor on the old element as in spl_ptr_llist_pop */ if (intern->llist->dtor) { intern->llist->dtor(element); } /* the element is replaced, delref the old one as in * SplDoublyLinkedList::pop() */ zval_ptr_dtor(&element->data); ZVAL_COPY_VALUE(&element->data, value); /* new element, call ctor as in spl_ptr_llist_push */ if (intern->llist->ctor) { intern->llist->ctor(element); } } else { zval_ptr_dtor(value); zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0); return; } } } /* }}} */
/* {{{ proto bool SplDoublyLinkedList::push(mixed value) Push $value on the SplDoublyLinkedList */ SPL_METHOD(SplDoublyLinkedList, push) { zval *value; spl_dllist_object *intern; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) { return; } intern = Z_SPLDLLIST_P(ZEND_THIS); spl_ptr_llist_push(intern->llist, value); RETURN_TRUE; }
static void spl_ptr_llist_copy(spl_ptr_llist *from, spl_ptr_llist *to) /* {{{ */ { spl_ptr_llist_element *current = from->head, *next; //??? spl_ptr_llist_ctor_func ctor = from->ctor; while (current) { next = current->next; /*??? FIXME if (ctor) { ctor(current); } */ spl_ptr_llist_push(to, ¤t->data); current = next; } }