Annotation of embedaddon/php/ext/spl/spl_dllist.c, revision 1.1.1.4

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3   misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Authors: Etienne Kneuss <colder@php.net>                             |
                     16:    +----------------------------------------------------------------------+
                     17:  */
                     18: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      20: 
                     21: #ifdef HAVE_CONFIG_H
                     22: # include "config.h"
                     23: #endif
                     24: 
                     25: #include "php.h"
                     26: #include "zend_exceptions.h"
                     27: #include "zend_hash.h"
                     28: 
                     29: #include "php_spl.h"
1.1.1.2   misho      30: #include "ext/standard/info.h"
                     31: #include "ext/standard/php_var.h"
                     32: #include "ext/standard/php_smart_str.h"
1.1       misho      33: #include "spl_functions.h"
                     34: #include "spl_engine.h"
                     35: #include "spl_iterators.h"
                     36: #include "spl_dllist.h"
                     37: #include "spl_exceptions.h"
                     38: 
                     39: zend_object_handlers spl_handler_SplDoublyLinkedList;
                     40: PHPAPI zend_class_entry  *spl_ce_SplDoublyLinkedList;
                     41: PHPAPI zend_class_entry  *spl_ce_SplQueue;
                     42: PHPAPI zend_class_entry  *spl_ce_SplStack;
                     43: 
                     44: #define SPL_LLIST_DELREF(elem) if(!--(elem)->rc) { \
                     45:        efree(elem); \
                     46:        elem = NULL; \
                     47: }
                     48: 
                     49: #define SPL_LLIST_CHECK_DELREF(elem) if((elem) && !--(elem)->rc) { \
                     50:        efree(elem); \
                     51:        elem = NULL; \
                     52: }
                     53: 
                     54: #define SPL_LLIST_ADDREF(elem) (elem)->rc++
                     55: #define SPL_LLIST_CHECK_ADDREF(elem) if(elem) (elem)->rc++
                     56: 
                     57: #define SPL_DLLIST_IT_DELETE 0x00000001 /* Delete flag makes the iterator delete the current element on next */
                     58: #define SPL_DLLIST_IT_LIFO   0x00000002 /* LIFO flag makes the iterator traverse the structure as a LastInFirstOut */
                     59: #define SPL_DLLIST_IT_MASK   0x00000003 /* Mask to isolate flags related to iterators */
                     60: #define SPL_DLLIST_IT_FIX    0x00000004 /* Backward/Forward bit is fixed */
                     61: 
                     62: #ifdef accept
                     63: #undef accept
                     64: #endif
                     65: 
                     66: typedef struct _spl_ptr_llist_element {
                     67:        struct _spl_ptr_llist_element *prev;
                     68:        struct _spl_ptr_llist_element *next;
                     69:        int                            rc;
                     70:        void                          *data;
                     71: } spl_ptr_llist_element;
                     72: 
                     73: typedef void (*spl_ptr_llist_dtor_func)(spl_ptr_llist_element * TSRMLS_DC);
                     74: typedef void (*spl_ptr_llist_ctor_func)(spl_ptr_llist_element * TSRMLS_DC);
                     75: 
                     76: typedef struct _spl_ptr_llist {
                     77:        spl_ptr_llist_element   *head;
                     78:        spl_ptr_llist_element   *tail;
                     79:        spl_ptr_llist_dtor_func  dtor;
                     80:        spl_ptr_llist_ctor_func  ctor;
                     81:        int count;
                     82: } spl_ptr_llist;
                     83: 
                     84: typedef struct _spl_dllist_object spl_dllist_object;
                     85: typedef struct _spl_dllist_it spl_dllist_it;
                     86: 
                     87: struct _spl_dllist_object {
                     88:        zend_object            std;
                     89:        spl_ptr_llist         *llist;
                     90:        int                    traverse_position;
                     91:        spl_ptr_llist_element *traverse_pointer;
                     92:        zval                  *retval;
                     93:        int                    flags;
                     94:        zend_function         *fptr_offset_get;
                     95:        zend_function         *fptr_offset_set;
                     96:        zend_function         *fptr_offset_has;
                     97:        zend_function         *fptr_offset_del;
                     98:        zend_function         *fptr_count;
                     99:        zend_class_entry      *ce_get_iterator;
                    100:        HashTable             *debug_info;
                    101: };
                    102: 
                    103: /* define an overloaded iterator structure */
                    104: struct _spl_dllist_it {
                    105:        zend_user_iterator     intern;
                    106:        int                    traverse_position;
                    107:        spl_ptr_llist_element *traverse_pointer;
                    108:        int                    flags;
                    109:        spl_dllist_object     *object;
                    110: };
                    111: 
                    112: /* {{{  spl_ptr_llist */
                    113: static void spl_ptr_llist_zval_dtor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */
                    114:        if (elem->data) {
                    115:                zval_ptr_dtor((zval **)&elem->data);
                    116:        }
                    117: }
                    118: /* }}} */
                    119: 
                    120: static void spl_ptr_llist_zval_ctor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */
                    121:        Z_ADDREF_P((zval *)elem->data);
                    122: }
                    123: /* }}} */
                    124: 
                    125: static spl_ptr_llist *spl_ptr_llist_init(spl_ptr_llist_ctor_func ctor, spl_ptr_llist_dtor_func dtor) /* {{{ */
                    126: {
                    127:        spl_ptr_llist *llist = emalloc(sizeof(spl_ptr_llist));
                    128: 
                    129:        llist->head  = NULL;
                    130:        llist->tail  = NULL;
                    131:        llist->count = 0;
                    132:        llist->dtor  = dtor;
                    133:        llist->ctor  = ctor;
                    134: 
                    135:        return llist;
                    136: }
                    137: /* }}} */
                    138: 
                    139: static long spl_ptr_llist_count(spl_ptr_llist *llist) /* {{{ */
                    140: {
                    141:        return (long)llist->count;
                    142: }
                    143: /* }}} */
                    144: 
                    145: static void spl_ptr_llist_destroy(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
                    146: {
                    147:        spl_ptr_llist_element   *current = llist->head, *next;
                    148:        spl_ptr_llist_dtor_func  dtor    = llist->dtor;
                    149: 
                    150:        while (current) {
                    151:                next = current->next;
                    152:                if(current && dtor) {
                    153:                        dtor(current TSRMLS_CC);
                    154:                }
                    155:                SPL_LLIST_DELREF(current);
                    156:                current = next;
                    157:        }
                    158: 
                    159:        efree(llist);
                    160: }
                    161: /* }}} */
                    162: 
                    163: static spl_ptr_llist_element *spl_ptr_llist_offset(spl_ptr_llist *llist, long offset, int backward) /* {{{ */
                    164: {
                    165: 
                    166:        spl_ptr_llist_element *current;
                    167:        int pos = 0;
                    168: 
                    169:        if (backward) {
                    170:                current = llist->tail;
                    171:        } else {
                    172:                current = llist->head;
                    173:        }
                    174: 
                    175:        while (current && pos < offset) {
                    176:                pos++;
                    177:                if (backward) {
                    178:                        current = current->prev;
                    179:                } else {
                    180:                        current = current->next;
                    181:                }
                    182:        }
                    183: 
                    184:        return current;
                    185: }
                    186: /* }}} */
                    187: 
                    188: static void spl_ptr_llist_unshift(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */
                    189: {
                    190:        spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
                    191: 
                    192:        elem->data = data;
                    193:        elem->rc   = 1;
                    194:        elem->prev = NULL;
                    195:        elem->next = llist->head;
                    196: 
                    197:        if (llist->head) {
                    198:                llist->head->prev = elem;
                    199:        } else {
                    200:                llist->tail = elem;
                    201:        }
                    202: 
                    203:        llist->head = elem;
                    204:        llist->count++;
                    205: 
                    206:        if (llist->ctor) {
                    207:                llist->ctor(elem TSRMLS_CC);
                    208:        }
                    209: }
                    210: /* }}} */
                    211: 
                    212: static void spl_ptr_llist_push(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */
                    213: {
                    214:        spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element));
                    215: 
                    216:        elem->data = data;
                    217:        elem->rc   = 1;
                    218:        elem->prev = llist->tail;
                    219:        elem->next = NULL;
                    220: 
                    221:        if (llist->tail) {
                    222:                llist->tail->next = elem;
                    223:        } else {
                    224:                llist->head = elem;
                    225:        }
                    226: 
                    227:        llist->tail = elem;
                    228:        llist->count++;
                    229: 
                    230:        if (llist->ctor) {
                    231:                llist->ctor(elem TSRMLS_CC);
                    232:        }
                    233: }
                    234: /* }}} */
                    235: 
                    236: static void *spl_ptr_llist_pop(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
                    237: {
                    238:        void                     *data;
                    239:        spl_ptr_llist_element    *tail = llist->tail;
                    240: 
                    241:        if (tail == NULL) {
                    242:                return NULL;
                    243:        }
                    244: 
                    245:        if (tail->prev) {
                    246:                tail->prev->next = NULL;
                    247:        } else {
                    248:                llist->head = NULL;
                    249:        }
                    250: 
                    251:        llist->tail = tail->prev;
                    252:        llist->count--;
                    253:        data = tail->data;
                    254: 
                    255:        if (llist->dtor) {
                    256:                llist->dtor(tail TSRMLS_CC);
                    257:        }
                    258: 
                    259:        tail->data = NULL;
                    260: 
                    261:        SPL_LLIST_DELREF(tail);
                    262: 
                    263:        return data;
                    264: }
                    265: /* }}} */
                    266: 
                    267: static void *spl_ptr_llist_last(spl_ptr_llist *llist) /* {{{ */
                    268: {
                    269:        spl_ptr_llist_element *tail = llist->tail;
                    270: 
                    271:        if (tail == NULL) {
                    272:                return NULL;
                    273:        } else {
                    274:                return tail->data;
                    275:        }
                    276: }
                    277: /* }}} */
                    278: 
                    279: static void *spl_ptr_llist_first(spl_ptr_llist *llist) /* {{{ */
                    280: {
                    281:        spl_ptr_llist_element *head = llist->head;
                    282: 
                    283:        if (head == NULL) {
                    284:                return NULL;
                    285:        } else {
                    286:                return head->data;
                    287:        }
                    288: }
                    289: /* }}} */
                    290: 
                    291: static void *spl_ptr_llist_shift(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */
                    292: {
                    293:        void                    *data;
                    294:        spl_ptr_llist_element   *head = llist->head;
                    295: 
                    296:        if (head == NULL) {
                    297:                return NULL;
                    298:        }
                    299: 
                    300:        if (head->next) {
                    301:                head->next->prev = NULL;
                    302:        } else {
                    303:                llist->tail = NULL;
                    304:        }
                    305: 
                    306:        llist->head = head->next;
                    307:        llist->count--;
                    308:        data = head->data;
                    309: 
                    310:        if (llist->dtor) {
                    311:                llist->dtor(head TSRMLS_CC);
                    312:        }
                    313:        head->data = NULL;
                    314: 
                    315:        SPL_LLIST_DELREF(head);
                    316: 
                    317:        return data;
                    318: }
                    319: /* }}} */
                    320: 
                    321: static void spl_ptr_llist_copy(spl_ptr_llist *from, spl_ptr_llist *to TSRMLS_DC) /* {{{ */
                    322: {
                    323:        spl_ptr_llist_element   *current = from->head, *next;
                    324:        spl_ptr_llist_ctor_func  ctor    = from->ctor;
                    325: 
                    326:        while (current) {
                    327:                next = current->next;
                    328: 
                    329:                if (ctor) {
                    330:                        ctor(current TSRMLS_CC);
                    331:                }
                    332: 
                    333:                spl_ptr_llist_push(to, current->data TSRMLS_CC);
                    334:                current = next;
                    335:        }
                    336: 
                    337: }
                    338: /* }}} */
                    339: 
                    340: /* }}} */
                    341: 
                    342: static void spl_dllist_object_free_storage(void *object TSRMLS_DC) /* {{{ */
                    343: {
                    344:        spl_dllist_object *intern = (spl_dllist_object *)object;
                    345:        zval              *tmp    = NULL;
                    346: 
                    347:        zend_object_std_dtor(&intern->std TSRMLS_CC);
                    348: 
                    349:        while(intern->llist->count > 0) {
                    350:                tmp = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC);
                    351:                zval_ptr_dtor(&tmp);
                    352:        }
                    353: 
                    354:        spl_ptr_llist_destroy(intern->llist TSRMLS_CC);
                    355:        SPL_LLIST_CHECK_DELREF(intern->traverse_pointer);
                    356:        zval_ptr_dtor(&intern->retval);
                    357: 
                    358:        if (intern->debug_info != NULL) {
                    359:                zend_hash_destroy(intern->debug_info);
                    360:                efree(intern->debug_info);
                    361:        }
                    362: 
                    363:        efree(object);
                    364: }
                    365: /* }}} */
                    366: 
                    367: zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
                    368: 
                    369: static zend_object_value spl_dllist_object_new_ex(zend_class_entry *class_type, spl_dllist_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */
                    370: {
1.1.1.4 ! misho     371:        zend_object_value  retval = {0};
1.1       misho     372:        spl_dllist_object *intern;
                    373:        zend_class_entry  *parent = class_type;
                    374:        int                inherited = 0;
                    375: 
                    376:        intern = ecalloc(1, sizeof(spl_dllist_object));
                    377:        *obj = intern;
                    378:        ALLOC_INIT_ZVAL(intern->retval);
                    379: 
                    380:        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
1.1.1.2   misho     381:        object_properties_init(&intern->std, class_type);
1.1       misho     382: 
                    383:        intern->flags = 0;
                    384:        intern->traverse_position = 0;
                    385:        intern->debug_info = NULL;
                    386: 
                    387:        if (orig) {
                    388:                spl_dllist_object *other = (spl_dllist_object*)zend_object_store_get_object(orig TSRMLS_CC);
                    389:                intern->ce_get_iterator = other->ce_get_iterator;
                    390: 
                    391:                if (clone_orig) {
                    392:                        intern->llist = (spl_ptr_llist *)spl_ptr_llist_init(other->llist->ctor, other->llist->dtor);
                    393:                        spl_ptr_llist_copy(other->llist, intern->llist TSRMLS_CC);
                    394:                        intern->traverse_pointer  = intern->llist->head;
                    395:                        SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
                    396:                } else {
                    397:                        intern->llist = other->llist;
                    398:                        intern->traverse_pointer  = intern->llist->head;
                    399:                        SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
                    400:                }
                    401: 
                    402:                intern->flags = other->flags;
                    403:        } else {
                    404:                intern->llist = (spl_ptr_llist *)spl_ptr_llist_init(spl_ptr_llist_zval_ctor, spl_ptr_llist_zval_dtor);
                    405:                intern->traverse_pointer  = intern->llist->head;
                    406:                SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer);
                    407:        }
                    408: 
                    409:        while (parent) {
                    410:                if (parent == spl_ce_SplStack) {
                    411:                        intern->flags |= (SPL_DLLIST_IT_FIX | SPL_DLLIST_IT_LIFO);
                    412:                        retval.handlers = &spl_handler_SplDoublyLinkedList;
                    413:                } else if (parent == spl_ce_SplQueue) {
                    414:                        intern->flags |= SPL_DLLIST_IT_FIX;
                    415:                        retval.handlers = &spl_handler_SplDoublyLinkedList;
                    416:                }
                    417: 
                    418:                if (parent == spl_ce_SplDoublyLinkedList) {
                    419:                        retval.handlers = &spl_handler_SplDoublyLinkedList;
                    420:                        break;
                    421:                }
                    422: 
                    423:                parent = parent->parent;
                    424:                inherited = 1;
                    425:        }
                    426: 
                    427:        retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_dllist_object_free_storage, NULL TSRMLS_CC);
                    428: 
                    429:        if (!parent) { /* this must never happen */
                    430:                php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplDoublyLinkedList");
                    431:        }
                    432:        if (inherited) {
                    433:                zend_hash_find(&class_type->function_table, "offsetget",    sizeof("offsetget"),    (void **) &intern->fptr_offset_get);
                    434:                if (intern->fptr_offset_get->common.scope == parent) {
                    435:                        intern->fptr_offset_get = NULL;
                    436:                }
                    437:                zend_hash_find(&class_type->function_table, "offsetset",    sizeof("offsetset"),    (void **) &intern->fptr_offset_set);
                    438:                if (intern->fptr_offset_set->common.scope == parent) {
                    439:                        intern->fptr_offset_set = NULL;
                    440:                }
                    441:                zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
                    442:                if (intern->fptr_offset_has->common.scope == parent) {
                    443:                        intern->fptr_offset_has = NULL;
                    444:                }
                    445:                zend_hash_find(&class_type->function_table, "offsetunset",  sizeof("offsetunset"),  (void **) &intern->fptr_offset_del);
                    446:                if (intern->fptr_offset_del->common.scope == parent) {
                    447:                        intern->fptr_offset_del = NULL;
                    448:                }
                    449:                zend_hash_find(&class_type->function_table, "count",        sizeof("count"),        (void **) &intern->fptr_count);
                    450:                if (intern->fptr_count->common.scope == parent) {
                    451:                        intern->fptr_count = NULL;
                    452:                }
                    453:        }
                    454: 
                    455:        return retval;
                    456: }
                    457: /* }}} */
                    458: 
                    459: static zend_object_value spl_dllist_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
                    460: {
                    461:        spl_dllist_object *tmp;
                    462:        return spl_dllist_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
                    463: }
                    464: /* }}} */
                    465: 
                    466: static zend_object_value spl_dllist_object_clone(zval *zobject TSRMLS_DC) /* {{{ */
                    467: {
                    468:        zend_object_value   new_obj_val;
                    469:        zend_object        *old_object;
                    470:        zend_object        *new_object;
                    471:        zend_object_handle  handle = Z_OBJ_HANDLE_P(zobject);
                    472:        spl_dllist_object  *intern;
                    473: 
                    474:        old_object  = zend_objects_get_address(zobject TSRMLS_CC);
                    475:        new_obj_val = spl_dllist_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
                    476:        new_object  = &intern->std;
                    477: 
                    478:        zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
                    479: 
                    480:        return new_obj_val;
                    481: }
                    482: /* }}} */
                    483: 
                    484: static int spl_dllist_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
                    485: {
                    486:        spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC);
                    487: 
                    488:        if (intern->fptr_count) {
                    489:                zval *rv;
                    490:                zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
                    491:                if (rv) {
                    492:                        zval_ptr_dtor(&intern->retval);
                    493:                        MAKE_STD_ZVAL(intern->retval);
                    494:                        ZVAL_ZVAL(intern->retval, rv, 1, 1);
                    495:                        convert_to_long(intern->retval);
                    496:                        *count = (long) Z_LVAL_P(intern->retval);
                    497:                        return SUCCESS;
                    498:                }
                    499:                *count = 0;
                    500:                return FAILURE;
                    501:        }
                    502: 
                    503:        *count = spl_ptr_llist_count(intern->llist);
                    504:        return SUCCESS;
                    505: } 
                    506: /* }}} */
                    507: 
                    508: static HashTable* spl_dllist_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{{ */
                    509: {
                    510:        spl_dllist_object     *intern  = (spl_dllist_object*)zend_object_store_get_object(obj TSRMLS_CC);
                    511:        spl_ptr_llist_element *current = intern->llist->head, *next;
                    512:        zval *tmp, zrv, *dllist_array;
                    513:        char *pnstr;
                    514:        int  pnlen;
                    515:        int  i = 0;
                    516: 
                    517:        *is_temp = 0;
                    518: 
                    519:        if (intern->debug_info == NULL) {
                    520:                ALLOC_HASHTABLE(intern->debug_info);
                    521:                zend_hash_init(intern->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
                    522:        }
                    523: 
                    524:        if (intern->debug_info->nApplyCount == 0) {
                    525:                INIT_PZVAL(&zrv);
                    526:                Z_ARRVAL(zrv) = intern->debug_info;
                    527: 
1.1.1.2   misho     528:                if (!intern->std.properties) {
                    529:                        rebuild_object_properties(&intern->std);
                    530:                }
1.1       misho     531:                zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
                    532: 
                    533:                pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC);
                    534:                add_assoc_long_ex(&zrv, pnstr, pnlen+1, intern->flags);
                    535:                efree(pnstr);
                    536: 
                    537:                ALLOC_INIT_ZVAL(dllist_array);
                    538:                array_init(dllist_array);
                    539: 
                    540:                while (current) {
                    541:                        next = current->next;
                    542: 
                    543:                        add_index_zval(dllist_array, i, (zval *)current->data);
                    544:                        Z_ADDREF_P(current->data);
                    545:                        i++;
                    546: 
                    547:                        current = next;
                    548:                }
                    549: 
                    550:                pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "dllist", sizeof("dllist")-1, &pnlen TSRMLS_CC);
                    551:                add_assoc_zval_ex(&zrv, pnstr, pnlen+1, dllist_array);
                    552:                efree(pnstr);
                    553:        }
                    554: 
                    555:        return intern->debug_info;
                    556: }
                    557: /* }}}} */
                    558: 
                    559: /* {{{ proto bool SplDoublyLinkedList::push(mixed $value) U
                    560:           Push $value on the SplDoublyLinkedList */
                    561: SPL_METHOD(SplDoublyLinkedList, push)
                    562: {
                    563:        zval *value;
                    564:        spl_dllist_object *intern;
                    565: 
                    566:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
                    567:                return;
                    568:        }
                    569: 
                    570:        SEPARATE_ARG_IF_REF(value);
                    571: 
                    572:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    573:        spl_ptr_llist_push(intern->llist, value TSRMLS_CC);
                    574: 
                    575:        RETURN_TRUE;
                    576: } 
                    577: /* }}} */
                    578: 
                    579: /* {{{ proto bool SplDoublyLinkedList::unshift(mixed $value) U
                    580:           Unshift $value on the SplDoublyLinkedList */
                    581: SPL_METHOD(SplDoublyLinkedList, unshift)
                    582: {
                    583:        zval *value;
                    584:        spl_dllist_object *intern;
                    585: 
                    586:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
                    587:                return;
                    588:        }
                    589: 
                    590:        SEPARATE_ARG_IF_REF(value);
                    591: 
                    592:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    593:        spl_ptr_llist_unshift(intern->llist, value TSRMLS_CC);
                    594: 
                    595:        RETURN_TRUE;
                    596: }
                    597: /* }}} */
                    598: 
                    599: /* {{{ proto mixed SplDoublyLinkedList::pop() U
                    600:           Pop an element out of the SplDoublyLinkedList */
                    601: SPL_METHOD(SplDoublyLinkedList, pop)
                    602: {
                    603:        zval *value;
                    604:        spl_dllist_object *intern;
                    605: 
                    606:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                    607:                return;
                    608:        }
                    609: 
                    610:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    611:        value = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC);
                    612: 
                    613:        if (value == NULL) {
                    614:                zend_throw_exception(spl_ce_RuntimeException, "Can't pop from an empty datastructure", 0 TSRMLS_CC);
                    615:                return;
                    616:        }
                    617: 
                    618:        RETURN_ZVAL(value, 1, 1);
                    619: } 
                    620: /* }}} */
                    621: 
                    622: /* {{{ proto mixed SplDoublyLinkedList::shift() U
                    623:           Shift an element out of the SplDoublyLinkedList */
                    624: SPL_METHOD(SplDoublyLinkedList, shift)
                    625: {
                    626:        zval *value;
                    627:        spl_dllist_object *intern;
                    628: 
                    629:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                    630:                return;
                    631:        }
                    632: 
                    633:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    634:        value  = (zval *)spl_ptr_llist_shift(intern->llist TSRMLS_CC);
                    635: 
                    636:        if (value == NULL) {
                    637:                zend_throw_exception(spl_ce_RuntimeException, "Can't shift from an empty datastructure", 0 TSRMLS_CC);
                    638:                return;
                    639:        }
                    640: 
                    641:        RETURN_ZVAL(value, 1, 1);
                    642: } 
                    643: /* }}} */
                    644: 
                    645: /* {{{ proto mixed SplDoublyLinkedList::top() U
                    646:           Peek at the top element of the SplDoublyLinkedList */
                    647: SPL_METHOD(SplDoublyLinkedList, top)
                    648: {
                    649:        zval *value;
                    650:        spl_dllist_object *intern;
                    651: 
                    652:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                    653:                return;
                    654:        }
                    655: 
                    656:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    657:        value  = (zval *)spl_ptr_llist_last(intern->llist);
                    658: 
                    659:        if (value == NULL) {
                    660:                zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0 TSRMLS_CC);
                    661:                return;
                    662:        }
                    663: 
                    664:        RETURN_ZVAL(value, 1, 0);
                    665: }
                    666: /* }}} */
                    667: 
                    668: /* {{{ proto mixed SplDoublyLinkedList::bottom() U
                    669:           Peek at the bottom element of the SplDoublyLinkedList */
                    670: SPL_METHOD(SplDoublyLinkedList, bottom)
                    671: {
                    672:        zval *value;
                    673:        spl_dllist_object *intern;
                    674: 
                    675:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                    676:                return;
                    677:        }
                    678: 
                    679:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    680:        value  = (zval *)spl_ptr_llist_first(intern->llist);
                    681: 
                    682:        if (value == NULL) {
                    683:                zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0 TSRMLS_CC);
                    684:                return;
                    685:        }
                    686: 
                    687:        RETURN_ZVAL(value, 1, 0);
                    688: }
                    689: /* }}} */
                    690: 
                    691: /* {{{ proto int SplDoublyLinkedList::count() U
                    692:  Return the number of elements in the datastructure. */
                    693: SPL_METHOD(SplDoublyLinkedList, count)
                    694: {
                    695:        long count;
                    696:        spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    697: 
                    698:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                    699:                return;
                    700:        }
                    701: 
                    702:        count = spl_ptr_llist_count(intern->llist);
                    703:        RETURN_LONG(count);
                    704: }
                    705: /* }}} */
                    706: 
                    707: /* {{{ proto int SplDoublyLinkedList::isEmpty() U
                    708:  Return true if the SplDoublyLinkedList is empty. */
                    709: SPL_METHOD(SplDoublyLinkedList, isEmpty)
                    710: {
                    711:        long count;
                    712: 
                    713:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                    714:                return;
                    715:        }
                    716: 
                    717:        spl_dllist_object_count_elements(getThis(), &count TSRMLS_CC);
                    718:        RETURN_BOOL(count==0);
                    719: }
                    720: /* }}} */
                    721: 
                    722: /* {{{ proto int SplDoublyLinkedList::setIteratorMode($flags) U
                    723:  Set the mode of iteration */
                    724: SPL_METHOD(SplDoublyLinkedList, setIteratorMode)
                    725: {
                    726:        long value;
                    727:        spl_dllist_object *intern;
                    728: 
                    729:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) {
                    730:                return;
                    731:        }
                    732: 
                    733:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    734: 
                    735:        if (intern->flags & SPL_DLLIST_IT_FIX
                    736:                && (intern->flags & SPL_DLLIST_IT_LIFO) != (value & SPL_DLLIST_IT_LIFO)) {
                    737:                zend_throw_exception(spl_ce_RuntimeException, "Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen", 0 TSRMLS_CC);
                    738:                return;
                    739:        }
                    740: 
                    741:        intern->flags = value & SPL_DLLIST_IT_MASK;
                    742: 
                    743:        RETURN_LONG(intern->flags);
                    744: }
                    745: /* }}} */
                    746: 
                    747: /* {{{ proto int SplDoublyLinkedList::getIteratorMode() U
                    748:  Return the mode of iteration */
                    749: SPL_METHOD(SplDoublyLinkedList, getIteratorMode)
                    750: {
                    751:        spl_dllist_object *intern;
                    752: 
                    753:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
                    754:                return;
                    755:        }
                    756: 
                    757:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    758: 
                    759:        RETURN_LONG(intern->flags);
                    760: }
                    761: /* }}} */
                    762: 
                    763: /* {{{ proto bool SplDoublyLinkedList::offsetExists(mixed $index) U
                    764:  Returns whether the requested $index exists. */
                    765: SPL_METHOD(SplDoublyLinkedList, offsetExists)
                    766: {
                    767:        zval              *zindex;
                    768:        spl_dllist_object *intern;
                    769:        long               index;
                    770: 
                    771:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
                    772:                return;
                    773:        }
                    774: 
                    775:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    776:        index  = spl_offset_convert_to_long(zindex TSRMLS_CC);
                    777: 
                    778:        RETURN_BOOL(index >= 0 && index < intern->llist->count);
                    779: } /* }}} */
                    780: 
                    781: /* {{{ proto mixed SplDoublyLinkedList::offsetGet(mixed $index) U
                    782:  Returns the value at the specified $index. */
                    783: SPL_METHOD(SplDoublyLinkedList, offsetGet)
                    784: {
                    785:        zval                  *zindex, *value;
                    786:        long                   index;
                    787:        spl_dllist_object     *intern;
                    788:        spl_ptr_llist_element *element;
                    789: 
                    790:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
                    791:                return;
                    792:        }
                    793: 
                    794:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    795:        index  = spl_offset_convert_to_long(zindex TSRMLS_CC);
                    796: 
                    797:     if (index < 0 || index >= intern->llist->count) {
                    798:                zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC);
                    799:                return;
                    800:        }
                    801: 
                    802:        element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
                    803: 
                    804:        if (element != NULL) {
                    805:                value = (zval *)element->data;
                    806:                RETURN_ZVAL(value, 1, 0);
                    807:        } else {
                    808:                zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
                    809:                return;
                    810:        }
                    811: } /* }}} */
                    812: 
                    813: /* {{{ proto void SplDoublyLinkedList::offsetSet(mixed $index, mixed $newval) U
                    814:  Sets the value at the specified $index to $newval. */
                    815: SPL_METHOD(SplDoublyLinkedList, offsetSet)
                    816: {
                    817:        zval                  *zindex, *value;
                    818:        spl_dllist_object     *intern;
                    819: 
                    820:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) {
                    821:                return;
                    822:        }
                    823:        SEPARATE_ARG_IF_REF(value);
                    824: 
                    825:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    826: 
                    827:        if (Z_TYPE_P(zindex) == IS_NULL) {
                    828:                /* $obj[] = ... */
                    829:                spl_ptr_llist_push(intern->llist, value TSRMLS_CC);
                    830:        } else {
                    831:                /* $obj[$foo] = ... */
                    832:                long                   index;
                    833:                spl_ptr_llist_element *element;
                    834: 
                    835:                index = spl_offset_convert_to_long(zindex TSRMLS_CC);
                    836: 
                    837:                if (index < 0 || index >= intern->llist->count) {
                    838:                        zval_ptr_dtor(&value);
                    839:                        zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC);
                    840:                        return;
                    841:                }
                    842: 
                    843:                element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
                    844: 
                    845:                if (element != NULL) {
                    846:                        /* call dtor on the old element as in spl_ptr_llist_pop */
                    847:                        if (intern->llist->dtor) {
                    848:                                intern->llist->dtor(element TSRMLS_CC);
                    849:                        }
                    850: 
                    851:                        /* the element is replaced, delref the old one as in
                    852:                         * SplDoublyLinkedList::pop() */
                    853:                        zval_ptr_dtor((zval **)&element->data);
                    854:                        element->data = value;
                    855: 
                    856:                        /* new element, call ctor as in spl_ptr_llist_push */
                    857:                        if (intern->llist->ctor) {
                    858:                                intern->llist->ctor(element TSRMLS_CC);
                    859:                        }
                    860:                } else {
                    861:                        zval_ptr_dtor(&value);
                    862:                        zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
                    863:                        return;
                    864:                }
                    865:        }
                    866: } /* }}} */
                    867: 
                    868: /* {{{ proto void SplDoublyLinkedList::offsetUnset(mixed $index) U
                    869:  Unsets the value at the specified $index. */
                    870: SPL_METHOD(SplDoublyLinkedList, offsetUnset)
                    871: {
                    872:        zval                  *zindex;
                    873:        long                   index;
                    874:        spl_dllist_object     *intern;
                    875:        spl_ptr_llist_element *element;
                    876:        spl_ptr_llist         *llist;
                    877: 
                    878:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
                    879:                return;
                    880:        }
                    881: 
                    882:        intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1.1.1.3   misho     883:        index  = spl_offset_convert_to_long(zindex TSRMLS_CC);
1.1       misho     884:     llist  = intern->llist;
                    885: 
                    886:     if (index < 0 || index >= intern->llist->count) {
                    887:                zend_throw_exception(spl_ce_OutOfRangeException, "Offset out of range", 0 TSRMLS_CC);
                    888:                return;
                    889:        }
                    890: 
                    891:        element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO);
                    892: 
                    893:        if (element != NULL) {
                    894:                /* connect the neightbors */
                    895:                if (element->prev) {
                    896:                        element->prev->next = element->next;
                    897:                }
                    898: 
                    899:                if (element->next) {
                    900:                        element->next->prev = element->prev;
                    901:                }
                    902: 
                    903:                /* take care of head/tail */
                    904:                if (element == llist->head) {
                    905:                        llist->head = element->next;
                    906:                }
                    907: 
                    908:                if (element == llist->tail) {
                    909:                        llist->tail = element->prev;
                    910:                }
                    911: 
                    912:                /* finally, delete the element */
                    913:                llist->count--;
                    914: 
                    915:                if(llist->dtor) {
                    916:                        llist->dtor(element TSRMLS_CC);
                    917:                }
                    918: 
                    919:                zval_ptr_dtor((zval **)&element->data);
                    920:                element->data = NULL;
                    921: 
                    922:                SPL_LLIST_DELREF(element);
                    923:        } else {
                    924:                zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC);
                    925:                return;
                    926:        }
                    927: } /* }}} */
                    928: 
                    929: static void spl_dllist_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
                    930: {
                    931:        spl_dllist_it *iterator = (spl_dllist_it *)iter;
                    932: 
                    933:        SPL_LLIST_CHECK_DELREF(iterator->traverse_pointer);
                    934: 
                    935:        zend_user_it_invalidate_current(iter TSRMLS_CC);
                    936:        zval_ptr_dtor((zval**)&iterator->intern.it.data);
                    937: 
                    938:        efree(iterator);
                    939: }
                    940: /* }}} */
                    941: 
                    942: static void spl_dllist_it_helper_rewind(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags TSRMLS_DC) /* {{{ */
                    943: {
                    944:        SPL_LLIST_CHECK_DELREF(*traverse_pointer_ptr);
                    945: 
                    946:        if (flags & SPL_DLLIST_IT_LIFO) {
                    947:                *traverse_position_ptr = llist->count-1;
                    948:                *traverse_pointer_ptr  = llist->tail;
                    949:        } else {
                    950:                *traverse_position_ptr = 0;
                    951:                *traverse_pointer_ptr  = llist->head;
                    952:        }
                    953: 
                    954:        SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
                    955: }
                    956: /* }}} */
                    957: 
                    958: static void spl_dllist_it_helper_move_forward(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags TSRMLS_DC) /* {{{ */
                    959: {
                    960:        if (*traverse_pointer_ptr) {
                    961:                spl_ptr_llist_element *old = *traverse_pointer_ptr;
                    962: 
                    963:                if (flags & SPL_DLLIST_IT_LIFO) {
                    964:                        *traverse_pointer_ptr = old->prev;
                    965:                        (*traverse_position_ptr)--;
                    966: 
                    967:                        if (flags & SPL_DLLIST_IT_DELETE) {
                    968:                                zval *prev = (zval *)spl_ptr_llist_pop(llist TSRMLS_CC);
                    969: 
                    970:                                if (prev) {
                    971:                                        zval_ptr_dtor((zval **)&prev);
                    972:                                }
                    973:                        }
                    974:                } else {
                    975:                        *traverse_pointer_ptr = old->next;
                    976: 
                    977:                        if (flags & SPL_DLLIST_IT_DELETE) {
                    978:                                zval *prev = (zval *)spl_ptr_llist_shift(llist TSRMLS_CC);
                    979: 
                    980:                                if (prev) {
                    981:                                        zval_ptr_dtor((zval **)&prev);
                    982:                                }
                    983:                        } else {
                    984:                                (*traverse_position_ptr)++;
                    985:                        }
                    986:                }
                    987: 
                    988:                SPL_LLIST_DELREF(old);
                    989:                SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr);
                    990:        }
                    991: }
                    992: /* }}} */
                    993: 
                    994: static void spl_dllist_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
                    995: {
                    996:        spl_dllist_it     *iterator = (spl_dllist_it *)iter;
                    997:        spl_dllist_object *object   = iterator->object;
                    998:        spl_ptr_llist     *llist    = object->llist;
                    999: 
                   1000:        spl_dllist_it_helper_rewind(&iterator->traverse_pointer, &iterator->traverse_position, llist, object->flags TSRMLS_CC);
                   1001: }
                   1002: /* }}} */
                   1003: 
                   1004: static int spl_dllist_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
                   1005: {
                   1006:        spl_dllist_it         *iterator = (spl_dllist_it *)iter;
                   1007:        spl_ptr_llist_element *element  = iterator->traverse_pointer;
                   1008: 
                   1009:        return (element != NULL ? SUCCESS : FAILURE);
                   1010: }
                   1011: /* }}} */
                   1012: 
                   1013: static void spl_dllist_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
                   1014: {
                   1015:        spl_dllist_it         *iterator = (spl_dllist_it *)iter;
                   1016:        spl_ptr_llist_element *element  = iterator->traverse_pointer;
                   1017: 
                   1018:        if (element == NULL || element->data == NULL) {
                   1019:                *data = NULL;
                   1020:        } else {
                   1021:                *data = (zval **)&element->data;
                   1022:        }
                   1023: }
                   1024: /* }}} */
                   1025: 
                   1026: static int spl_dllist_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
                   1027: {
                   1028:        spl_dllist_it *iterator = (spl_dllist_it *)iter;
                   1029: 
                   1030:        *int_key = (ulong) iterator->traverse_position;
                   1031:        return HASH_KEY_IS_LONG;
                   1032: }
                   1033: /* }}} */
                   1034: 
                   1035: static void spl_dllist_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
                   1036: {
                   1037:        spl_dllist_it     *iterator = (spl_dllist_it *)iter;
                   1038:        spl_dllist_object *object   = iterator->object;
                   1039: 
                   1040:        zend_user_it_invalidate_current(iter TSRMLS_CC);
                   1041: 
                   1042:        spl_dllist_it_helper_move_forward(&iterator->traverse_pointer, &iterator->traverse_position, object->llist, object->flags TSRMLS_CC);
                   1043: }
                   1044: /* }}} */
                   1045: 
                   1046: /* {{{  proto int SplDoublyLinkedList::key() U
                   1047:    Return current array key */
                   1048: SPL_METHOD(SplDoublyLinkedList, key)
                   1049: {
                   1050:        spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1051:        
                   1052:        if (zend_parse_parameters_none() == FAILURE) {
                   1053:                return;
                   1054:        }
                   1055: 
                   1056:        RETURN_LONG(intern->traverse_position);
                   1057: }
                   1058: /* }}} */
                   1059: 
                   1060: /* {{{ proto void SplDoublyLinkedList::prev() U
                   1061:    Move to next entry */
                   1062: SPL_METHOD(SplDoublyLinkedList, prev)
                   1063: {
                   1064:        spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1065:        
                   1066:        if (zend_parse_parameters_none() == FAILURE) {
                   1067:                return;
                   1068:        }
                   1069: 
                   1070:        spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags ^ SPL_DLLIST_IT_LIFO TSRMLS_CC);
                   1071: }
                   1072: /* }}} */
                   1073: 
                   1074: /* {{{ proto void SplDoublyLinkedList::next() U
                   1075:    Move to next entry */
                   1076: SPL_METHOD(SplDoublyLinkedList, next)
                   1077: {
                   1078:        spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1079:        
                   1080:        if (zend_parse_parameters_none() == FAILURE) {
                   1081:                return;
                   1082:        }
                   1083: 
                   1084:        spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC);
                   1085: }
                   1086: /* }}} */
                   1087: 
                   1088: /* {{{ proto bool SplDoublyLinkedList::valid() U
                   1089:    Check whether the datastructure contains more entries */
                   1090: SPL_METHOD(SplDoublyLinkedList, valid)
                   1091: {
                   1092:        spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1093:        
                   1094:        if (zend_parse_parameters_none() == FAILURE) {
                   1095:                return;
                   1096:        }
                   1097: 
                   1098:        RETURN_BOOL(intern->traverse_pointer != NULL);
                   1099: }
                   1100: /* }}} */
                   1101: 
                   1102: /* {{{ proto void SplDoublyLinkedList::rewind() U
                   1103:    Rewind the datastructure back to the start */
                   1104: SPL_METHOD(SplDoublyLinkedList, rewind)
                   1105: {
                   1106:        spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1107:        
                   1108:        if (zend_parse_parameters_none() == FAILURE) {
                   1109:                return;
                   1110:        }
                   1111: 
                   1112:        spl_dllist_it_helper_rewind(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC);
                   1113: }
                   1114: /* }}} */
                   1115: 
                   1116: /* {{{ proto mixed|NULL SplDoublyLinkedList::current() U
                   1117:    Return current datastructure entry */
                   1118: SPL_METHOD(SplDoublyLinkedList, current)
                   1119: {
                   1120:        spl_dllist_object     *intern  = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1121:        spl_ptr_llist_element *element = intern->traverse_pointer;
                   1122:        
                   1123:        if (zend_parse_parameters_none() == FAILURE) {
                   1124:                return;
                   1125:        }
                   1126: 
                   1127:        if (element == NULL || element->data == NULL) {
                   1128:                RETURN_NULL();
                   1129:        } else {
                   1130:                zval *data    = (zval *)element->data;
                   1131:                RETURN_ZVAL(data, 1, 0);
                   1132:        }
                   1133: }
                   1134: /* }}} */
1.1.1.2   misho    1135: /* {{{ proto string SplDoublyLinkedList::serialize()
                   1136:  Serializes storage */
                   1137: SPL_METHOD(SplDoublyLinkedList, serialize)
                   1138: {
                   1139:        spl_dllist_object     *intern   = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1140:        smart_str              buf      = {0};
                   1141:        spl_ptr_llist_element *current  = intern->llist->head, *next;
                   1142:     zval                   *flags;
                   1143:        php_serialize_data_t   var_hash;
                   1144: 
                   1145:        if (zend_parse_parameters_none() == FAILURE) {
                   1146:                return;
                   1147:        }
                   1148: 
                   1149:        PHP_VAR_SERIALIZE_INIT(var_hash);
                   1150: 
                   1151:        /* flags */
                   1152:        MAKE_STD_ZVAL(flags);
                   1153:        ZVAL_LONG(flags, intern->flags);
                   1154:        php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC);
                   1155:        zval_ptr_dtor(&flags);
                   1156: 
                   1157:        /* elements */
                   1158:        while (current) {
                   1159:                smart_str_appendc(&buf, ':');
                   1160:                next = current->next;
                   1161: 
                   1162:                php_var_serialize(&buf, (zval **)&current->data, &var_hash TSRMLS_CC);
                   1163: 
                   1164:                current = next;
                   1165:        }
                   1166: 
                   1167:        smart_str_0(&buf);
                   1168: 
                   1169:        /* done */
                   1170:        PHP_VAR_SERIALIZE_DESTROY(var_hash);
                   1171: 
                   1172:        if (buf.c) {
                   1173:                RETURN_STRINGL(buf.c, buf.len, 0);
                   1174:        } else {
                   1175:                RETURN_NULL();
                   1176:        }
                   1177:        
                   1178: } /* }}} */
                   1179: 
                   1180: /* {{{ proto void SplDoublyLinkedList::unserialize(string serialized)
                   1181:  Unserializes storage */
                   1182: SPL_METHOD(SplDoublyLinkedList, unserialize)
                   1183: {
                   1184:        spl_dllist_object     *intern   = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1185:        zval                  *flags, *elem;
                   1186:        char *buf;
                   1187:        int buf_len;
                   1188:        const unsigned char *p, *s;
                   1189:        php_unserialize_data_t var_hash;
                   1190:        
                   1191:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
                   1192:                return;
                   1193:        }
                   1194: 
                   1195:        if (buf_len == 0) {
                   1196:                zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Serialized string cannot be empty");
                   1197:                return;
                   1198:        }
                   1199: 
                   1200:        s = p = (const unsigned char*)buf;
                   1201:        PHP_VAR_UNSERIALIZE_INIT(var_hash);
                   1202: 
                   1203:        /* flags */
                   1204:        ALLOC_INIT_ZVAL(flags);
                   1205:        if (!php_var_unserialize(&flags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(flags) != IS_LONG) {
                   1206:                zval_ptr_dtor(&flags);
                   1207:                goto error;
                   1208:        }
                   1209:        intern->flags = Z_LVAL_P(flags);
                   1210:        zval_ptr_dtor(&flags);
                   1211: 
                   1212:        /* elements */
                   1213:        while(*p == ':') {
                   1214:                ++p;
                   1215:                ALLOC_INIT_ZVAL(elem);
                   1216:                if (!php_var_unserialize(&elem, &p, s + buf_len, &var_hash TSRMLS_CC)) {
                   1217:                        zval_ptr_dtor(&elem);
                   1218:                        goto error;
                   1219:                }
                   1220: 
                   1221:                spl_ptr_llist_push(intern->llist, elem TSRMLS_CC);
                   1222:        }
                   1223: 
                   1224:        if (*p != '\0') {
                   1225:                goto error;
                   1226:        }
                   1227: 
                   1228:        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
                   1229:        return;
                   1230: 
                   1231: error:
                   1232:        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
                   1233:        zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
                   1234:        return;
                   1235: 
                   1236: } /* }}} */
1.1       misho    1237: 
                   1238: /* iterator handler table */
                   1239: zend_object_iterator_funcs spl_dllist_it_funcs = {
                   1240:        spl_dllist_it_dtor,
                   1241:        spl_dllist_it_valid,
                   1242:        spl_dllist_it_get_current_data,
                   1243:        spl_dllist_it_get_current_key,
                   1244:        spl_dllist_it_move_forward,
                   1245:        spl_dllist_it_rewind
                   1246: };
                   1247: 
                   1248: zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
                   1249: {
                   1250:        spl_dllist_it     *iterator;
                   1251:        spl_dllist_object *dllist_object = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1252: 
                   1253:        if (by_ref) {
                   1254:                zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC);
                   1255:                return NULL;
                   1256:        }
                   1257: 
                   1258:        Z_ADDREF_P(object);
                   1259: 
                   1260:        iterator                     = emalloc(sizeof(spl_dllist_it));
                   1261:        iterator->intern.it.data     = (void*)object;
                   1262:        iterator->intern.it.funcs    = &spl_dllist_it_funcs;
                   1263:        iterator->intern.ce          = ce;
                   1264:        iterator->intern.value       = NULL;
                   1265:        iterator->traverse_position  = dllist_object->traverse_position;
                   1266:        iterator->traverse_pointer   = dllist_object->traverse_pointer;
                   1267:        iterator->flags              = dllist_object->flags & SPL_DLLIST_IT_MASK;
                   1268:        iterator->object             = dllist_object;
                   1269: 
                   1270:        SPL_LLIST_CHECK_ADDREF(iterator->traverse_pointer);
                   1271: 
                   1272: 
                   1273:        return (zend_object_iterator*)iterator;
                   1274: }
                   1275: /* }}} */
                   1276: 
                   1277: /*  Function/Class/Method definitions */
                   1278: ZEND_BEGIN_ARG_INFO(arginfo_dllist_setiteratormode, 0)
                   1279:        ZEND_ARG_INFO(0, flags)
                   1280: ZEND_END_ARG_INFO()
                   1281: 
                   1282: ZEND_BEGIN_ARG_INFO(arginfo_dllist_push, 0)
                   1283:        ZEND_ARG_INFO(0, value)
                   1284: ZEND_END_ARG_INFO()
                   1285: 
                   1286: ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetGet, 0, 0, 1)
                   1287:        ZEND_ARG_INFO(0, index)
                   1288: ZEND_END_ARG_INFO()
                   1289: 
                   1290: ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetSet, 0, 0, 2)
                   1291:        ZEND_ARG_INFO(0, index)
                   1292:        ZEND_ARG_INFO(0, newval)
                   1293: ZEND_END_ARG_INFO()
                   1294: 
                   1295: ZEND_BEGIN_ARG_INFO(arginfo_dllist_void, 0)
                   1296: ZEND_END_ARG_INFO()
                   1297: 
1.1.1.2   misho    1298: ZEND_BEGIN_ARG_INFO(arginfo_dllist_serialized, 0)
                   1299:        ZEND_ARG_INFO(0, serialized)
                   1300: ZEND_END_ARG_INFO();
                   1301: 
1.1       misho    1302: static const zend_function_entry spl_funcs_SplQueue[] = {
                   1303:        SPL_MA(SplQueue, enqueue, SplDoublyLinkedList, push,  arginfo_dllist_push, ZEND_ACC_PUBLIC)
                   1304:        SPL_MA(SplQueue, dequeue, SplDoublyLinkedList, shift, arginfo_dllist_void, ZEND_ACC_PUBLIC)
                   1305:        PHP_FE_END
                   1306: };
                   1307: 
                   1308: static const zend_function_entry spl_funcs_SplDoublyLinkedList[] = {
                   1309:        SPL_ME(SplDoublyLinkedList, pop,             arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1310:        SPL_ME(SplDoublyLinkedList, shift,           arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1311:        SPL_ME(SplDoublyLinkedList, push,            arginfo_dllist_push,            ZEND_ACC_PUBLIC)
                   1312:        SPL_ME(SplDoublyLinkedList, unshift,         arginfo_dllist_push,            ZEND_ACC_PUBLIC)
                   1313:        SPL_ME(SplDoublyLinkedList, top,             arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1314:        SPL_ME(SplDoublyLinkedList, bottom,          arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1315:        SPL_ME(SplDoublyLinkedList, isEmpty,         arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1316:        SPL_ME(SplDoublyLinkedList, setIteratorMode, arginfo_dllist_setiteratormode, ZEND_ACC_PUBLIC)
                   1317:        SPL_ME(SplDoublyLinkedList, getIteratorMode, arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1.1.1.2   misho    1318:        /* Countable */
                   1319:        SPL_ME(SplDoublyLinkedList, count,           arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1320:        /* ArrayAccess */
1.1       misho    1321:        SPL_ME(SplDoublyLinkedList, offsetExists,    arginfo_dllist_offsetGet,       ZEND_ACC_PUBLIC)
                   1322:        SPL_ME(SplDoublyLinkedList, offsetGet,       arginfo_dllist_offsetGet,       ZEND_ACC_PUBLIC)
                   1323:        SPL_ME(SplDoublyLinkedList, offsetSet,       arginfo_dllist_offsetSet,       ZEND_ACC_PUBLIC)
                   1324:        SPL_ME(SplDoublyLinkedList, offsetUnset,     arginfo_dllist_offsetGet,       ZEND_ACC_PUBLIC)
1.1.1.2   misho    1325:        /* Iterator */
1.1       misho    1326:        SPL_ME(SplDoublyLinkedList, rewind,          arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1327:        SPL_ME(SplDoublyLinkedList, current,         arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1328:        SPL_ME(SplDoublyLinkedList, key,             arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1329:        SPL_ME(SplDoublyLinkedList, next,            arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1330:        SPL_ME(SplDoublyLinkedList, prev,            arginfo_dllist_void,            ZEND_ACC_PUBLIC)
                   1331:        SPL_ME(SplDoublyLinkedList, valid,           arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1.1.1.2   misho    1332:        /* Serializable */
                   1333:        SPL_ME(SplDoublyLinkedList,  unserialize,    arginfo_dllist_serialized,      ZEND_ACC_PUBLIC)
                   1334:        SPL_ME(SplDoublyLinkedList,  serialize,      arginfo_dllist_void,            ZEND_ACC_PUBLIC)
1.1       misho    1335:        PHP_FE_END
                   1336: };
                   1337: /* }}} */
                   1338: 
                   1339: PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */
                   1340: {
                   1341:        REGISTER_SPL_STD_CLASS_EX(SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplDoublyLinkedList);
                   1342:        memcpy(&spl_handler_SplDoublyLinkedList, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
                   1343: 
                   1344:        spl_handler_SplDoublyLinkedList.clone_obj      = spl_dllist_object_clone;
                   1345:        spl_handler_SplDoublyLinkedList.count_elements = spl_dllist_object_count_elements;
                   1346:        spl_handler_SplDoublyLinkedList.get_debug_info = spl_dllist_object_get_debug_info;
                   1347: 
                   1348:        REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_LIFO",  SPL_DLLIST_IT_LIFO);
                   1349:        REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_FIFO",  0);
                   1350:        REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_DELETE",SPL_DLLIST_IT_DELETE);
                   1351:        REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_KEEP",  0);
                   1352: 
                   1353:        REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Iterator);
                   1354:        REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Countable);
                   1355:        REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, ArrayAccess);
1.1.1.2   misho    1356:        REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Serializable);
1.1       misho    1357: 
                   1358:        spl_ce_SplDoublyLinkedList->get_iterator = spl_dllist_get_iterator;
                   1359: 
                   1360:        REGISTER_SPL_SUB_CLASS_EX(SplQueue,           SplDoublyLinkedList,        spl_dllist_object_new, spl_funcs_SplQueue);
                   1361:        REGISTER_SPL_SUB_CLASS_EX(SplStack,           SplDoublyLinkedList,        spl_dllist_object_new, NULL);
                   1362: 
                   1363:        spl_ce_SplQueue->get_iterator = spl_dllist_get_iterator;
                   1364:        spl_ce_SplStack->get_iterator = spl_dllist_get_iterator;
                   1365: 
                   1366:        return SUCCESS;
                   1367: }
                   1368: /* }}} */
                   1369: /*
                   1370:  * Local variables:
                   1371:  * tab-width: 4
                   1372:  * c-basic-offset: 4
                   1373:  * End:
                   1374:  * vim600: fdm=marker
                   1375:  * vim: noet sw=4 ts=4
                   1376:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>