root/ext/spl/spl_fixedarray.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. spl_fixed_array_from_obj
  3. spl_fixedarray_init
  4. spl_fixedarray_resize
  5. spl_fixedarray_copy
  6. spl_fixedarray_object_get_gc
  7. spl_fixedarray_object_get_properties
  8. spl_fixedarray_object_free_storage
  9. spl_fixedarray_object_new_ex
  10. spl_fixedarray_new
  11. spl_fixedarray_object_clone
  12. spl_fixedarray_object_read_dimension_helper
  13. spl_fixedarray_object_read_dimension
  14. spl_fixedarray_object_write_dimension_helper
  15. spl_fixedarray_object_write_dimension
  16. spl_fixedarray_object_unset_dimension_helper
  17. spl_fixedarray_object_unset_dimension
  18. spl_fixedarray_object_has_dimension_helper
  19. spl_fixedarray_object_has_dimension
  20. spl_fixedarray_object_count_elements
  21. SPL_METHOD
  22. SPL_METHOD
  23. SPL_METHOD
  24. SPL_METHOD
  25. SPL_METHOD
  26. SPL_METHOD
  27. SPL_METHOD
  28. SPL_METHOD
  29. SPL_METHOD
  30. SPL_METHOD
  31. SPL_METHOD
  32. spl_fixedarray_it_dtor
  33. spl_fixedarray_it_rewind
  34. spl_fixedarray_it_valid
  35. spl_fixedarray_it_get_current_data
  36. spl_fixedarray_it_get_current_key
  37. spl_fixedarray_it_move_forward
  38. SPL_METHOD
  39. SPL_METHOD
  40. SPL_METHOD
  41. SPL_METHOD
  42. SPL_METHOD
  43. spl_fixedarray_get_iterator
  44. PHP_MINIT_FUNCTION

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 The PHP Group                                |
   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   | Author: Antony Dovgal <tony@daylessday.org>                          |
  16   |         Etienne Kneuss <colder@php.net>                              |
  17   +----------------------------------------------------------------------+
  18 */
  19 
  20 /* $Id$ */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 #include "config.h"
  24 #endif
  25 
  26 #include "php.h"
  27 #include "php_ini.h"
  28 #include "ext/standard/info.h"
  29 #include "zend_exceptions.h"
  30 
  31 #include "php_spl.h"
  32 #include "spl_functions.h"
  33 #include "spl_engine.h"
  34 #include "spl_fixedarray.h"
  35 #include "spl_exceptions.h"
  36 #include "spl_iterators.h"
  37 
  38 zend_object_handlers spl_handler_SplFixedArray;
  39 PHPAPI zend_class_entry *spl_ce_SplFixedArray;
  40 
  41 #ifdef COMPILE_DL_SPL_FIXEDARRAY
  42 ZEND_GET_MODULE(spl_fixedarray)
  43 #endif
  44 
  45 typedef struct _spl_fixedarray { /* {{{ */
  46         zend_long size;
  47         zval *elements;
  48 } spl_fixedarray;
  49 /* }}} */
  50 
  51 typedef struct _spl_fixedarray_object { /* {{{ */
  52         spl_fixedarray        *array;
  53         zend_function         *fptr_offset_get;
  54         zend_function         *fptr_offset_set;
  55         zend_function         *fptr_offset_has;
  56         zend_function         *fptr_offset_del;
  57         zend_function         *fptr_count;
  58         int                    current;
  59         int                    flags;
  60         zend_class_entry      *ce_get_iterator;
  61         zend_object            std;
  62 } spl_fixedarray_object;
  63 /* }}} */
  64 
  65 typedef struct _spl_fixedarray_it { /* {{{ */
  66         zend_user_iterator     intern;
  67 } spl_fixedarray_it;
  68 /* }}} */
  69 
  70 #define SPL_FIXEDARRAY_OVERLOADED_REWIND  0x0001
  71 #define SPL_FIXEDARRAY_OVERLOADED_VALID   0x0002
  72 #define SPL_FIXEDARRAY_OVERLOADED_KEY     0x0004
  73 #define SPL_FIXEDARRAY_OVERLOADED_CURRENT 0x0008
  74 #define SPL_FIXEDARRAY_OVERLOADED_NEXT    0x0010
  75 
  76 static inline spl_fixedarray_object *spl_fixed_array_from_obj(zend_object *obj) /* {{{ */ {
  77         return (spl_fixedarray_object*)((char*)(obj) - XtOffsetOf(spl_fixedarray_object, std));
  78 }
  79 /* }}} */
  80 
  81 #define Z_SPLFIXEDARRAY_P(zv)  spl_fixed_array_from_obj(Z_OBJ_P((zv)))
  82 
  83 static void spl_fixedarray_init(spl_fixedarray *array, zend_long size) /* {{{ */
  84 {
  85         if (size > 0) {
  86                 array->size = 0; /* reset size in case ecalloc() fails */
  87                 array->elements = ecalloc(size, sizeof(zval));
  88                 array->size = size;
  89         } else {
  90                 array->elements = NULL;
  91                 array->size = 0;
  92         }
  93 }
  94 /* }}} */
  95 
  96 static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size) /* {{{ */
  97 {
  98         if (size == array->size) {
  99                 /* nothing to do */
 100                 return;
 101         }
 102 
 103         /* first initialization */
 104         if (array->size == 0) {
 105                 spl_fixedarray_init(array, size);
 106                 return;
 107         }
 108 
 109         /* clearing the array */
 110         if (size == 0) {
 111                 zend_long i;
 112 
 113                 for (i = 0; i < array->size; i++) {
 114                         zval_ptr_dtor(&(array->elements[i]));
 115                 }
 116 
 117                 if (array->elements) {
 118                         efree(array->elements);
 119                         array->elements = NULL;
 120                 }
 121         } else if (size > array->size) {
 122                 array->elements = safe_erealloc(array->elements, size, sizeof(zval), 0);
 123                 memset(array->elements + array->size, '\0', sizeof(zval) * (size - array->size));
 124         } else { /* size < array->size */
 125                 zend_long i;
 126 
 127                 for (i = size; i < array->size; i++) {
 128                         zval_ptr_dtor(&(array->elements[i]));
 129                 }
 130                 array->elements = erealloc(array->elements, sizeof(zval) * size);
 131         }
 132 
 133         array->size = size;
 134 }
 135 /* }}} */
 136 
 137 static void spl_fixedarray_copy(spl_fixedarray *to, spl_fixedarray *from) /* {{{ */
 138 {
 139         int i;
 140         for (i = 0; i < from->size; i++) {
 141                 ZVAL_COPY(&to->elements[i], &from->elements[i]);
 142         }
 143 }
 144 /* }}} */
 145 
 146 static HashTable* spl_fixedarray_object_get_gc(zval *obj, zval **table, int *n) /* {{{{ */
 147 {
 148         spl_fixedarray_object *intern  = Z_SPLFIXEDARRAY_P(obj);
 149         HashTable *ht = zend_std_get_properties(obj);
 150 
 151         if (intern->array) {
 152                 *table = intern->array->elements;
 153                 *n = (int)intern->array->size;
 154         } else {
 155                 *table = NULL;
 156                 *n = 0;
 157         }
 158 
 159         return ht;
 160 }
 161 /* }}}} */
 162 
 163 static HashTable* spl_fixedarray_object_get_properties(zval *obj) /* {{{{ */
 164 {
 165         spl_fixedarray_object *intern  = Z_SPLFIXEDARRAY_P(obj);
 166         HashTable *ht = zend_std_get_properties(obj);
 167         zend_long  i = 0;
 168 
 169         if (intern->array) {
 170                 zend_long j = zend_hash_num_elements(ht);
 171 
 172                 for (i = 0; i < intern->array->size; i++) {
 173                         if (!Z_ISUNDEF(intern->array->elements[i])) {
 174                                 zend_hash_index_update(ht, i, &intern->array->elements[i]);
 175                                 if (Z_REFCOUNTED(intern->array->elements[i])){
 176                                         Z_ADDREF(intern->array->elements[i]);
 177                                 }
 178                         } else {
 179                                 zend_hash_index_update(ht, i, &EG(uninitialized_zval));
 180                         }
 181                 }
 182                 if (j > intern->array->size) {
 183                         for (i = intern->array->size; i < j; ++i) {
 184                                 zend_hash_index_del(ht, i);
 185                         }
 186                 }
 187         }
 188 
 189         return ht;
 190 }
 191 /* }}}} */
 192 
 193 static void spl_fixedarray_object_free_storage(zend_object *object) /* {{{ */
 194 {
 195         spl_fixedarray_object *intern = spl_fixed_array_from_obj(object);
 196         zend_long i;
 197 
 198         if (intern->array) {
 199                 for (i = 0; i < intern->array->size; i++) {
 200                         zval_ptr_dtor(&(intern->array->elements[i]));
 201                 }
 202 
 203                 if (intern->array->size > 0 && intern->array->elements) {
 204                         efree(intern->array->elements);
 205                 }
 206                 efree(intern->array);
 207         }
 208 
 209         zend_object_std_dtor(&intern->std);
 210 }
 211 /* }}} */
 212 
 213 zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref);
 214 
 215 static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, zval *orig, int clone_orig) /* {{{ */
 216 {
 217         spl_fixedarray_object *intern;
 218         zend_class_entry     *parent = class_type;
 219         int                   inherited = 0;
 220 
 221         intern = ecalloc(1, sizeof(spl_fixedarray_object) + zend_object_properties_size(parent));
 222 
 223         zend_object_std_init(&intern->std, class_type);
 224         object_properties_init(&intern->std, class_type);
 225 
 226         intern->current = 0;
 227         intern->flags = 0;
 228 
 229         if (orig && clone_orig) {
 230                 spl_fixedarray_object *other = Z_SPLFIXEDARRAY_P(orig);
 231                 intern->ce_get_iterator = other->ce_get_iterator;
 232                 if (!other->array) {
 233                         /* leave a empty object, will be dtor later by CLONE handler */
 234                         zend_throw_exception(spl_ce_RuntimeException, "The instance wasn't initialized properly", 0);
 235                 } else {
 236                         intern->array = emalloc(sizeof(spl_fixedarray));
 237                         spl_fixedarray_init(intern->array, other->array->size);
 238                         spl_fixedarray_copy(intern->array, other->array);
 239                 }
 240         }
 241 
 242         while (parent) {
 243                 if (parent == spl_ce_SplFixedArray) {
 244                         intern->std.handlers = &spl_handler_SplFixedArray;
 245                         class_type->get_iterator = spl_fixedarray_get_iterator;
 246                         break;
 247                 }
 248 
 249                 parent = parent->parent;
 250                 inherited = 1;
 251         }
 252 
 253         if (!parent) { /* this must never happen */
 254                 php_error_docref(NULL, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFixedArray");
 255         }
 256 
 257         if (!class_type->iterator_funcs.zf_current) {
 258                 class_type->iterator_funcs.zf_rewind = zend_hash_str_find_ptr(&class_type->function_table, "rewind", sizeof("rewind") - 1);
 259                 class_type->iterator_funcs.zf_valid = zend_hash_str_find_ptr(&class_type->function_table, "valid", sizeof("valid") - 1);
 260                 class_type->iterator_funcs.zf_key = zend_hash_str_find_ptr(&class_type->function_table, "key", sizeof("key") - 1);
 261                 class_type->iterator_funcs.zf_current = zend_hash_str_find_ptr(&class_type->function_table, "current", sizeof("current") - 1);
 262                 class_type->iterator_funcs.zf_next = zend_hash_str_find_ptr(&class_type->function_table, "next", sizeof("next") - 1);
 263         }
 264         if (inherited) {
 265                 if (class_type->iterator_funcs.zf_rewind->common.scope  != parent) {
 266                         intern->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND;
 267                 }
 268                 if (class_type->iterator_funcs.zf_valid->common.scope   != parent) {
 269                         intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID;
 270                 }
 271                 if (class_type->iterator_funcs.zf_key->common.scope     != parent) {
 272                         intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY;
 273                 }
 274                 if (class_type->iterator_funcs.zf_current->common.scope != parent) {
 275                         intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT;
 276                 }
 277                 if (class_type->iterator_funcs.zf_next->common.scope    != parent) {
 278                         intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT;
 279                 }
 280 
 281                 intern->fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1);
 282                 if (intern->fptr_offset_get->common.scope == parent) {
 283                         intern->fptr_offset_get = NULL;
 284                 }
 285                 intern->fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1);
 286                 if (intern->fptr_offset_set->common.scope == parent) {
 287                         intern->fptr_offset_set = NULL;
 288                 }
 289                 intern->fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1);
 290                 if (intern->fptr_offset_has->common.scope == parent) {
 291                         intern->fptr_offset_has = NULL;
 292                 }
 293                 intern->fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1);
 294                 if (intern->fptr_offset_del->common.scope == parent) {
 295                         intern->fptr_offset_del = NULL;
 296                 }
 297                 intern->fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1);
 298                 if (intern->fptr_count->common.scope == parent) {
 299                         intern->fptr_count = NULL;
 300                 }
 301         }
 302 
 303         return &intern->std;
 304 }
 305 /* }}} */
 306 
 307 static zend_object *spl_fixedarray_new(zend_class_entry *class_type) /* {{{ */
 308 {
 309         return spl_fixedarray_object_new_ex(class_type, NULL, 0);
 310 }
 311 /* }}} */
 312 
 313 static zend_object *spl_fixedarray_object_clone(zval *zobject) /* {{{ */
 314 {
 315         zend_object *old_object;
 316         zend_object *new_object;
 317 
 318         old_object  = Z_OBJ_P(zobject);
 319         new_object = spl_fixedarray_object_new_ex(old_object->ce, zobject, 1);
 320 
 321         zend_objects_clone_members(new_object, old_object);
 322 
 323         return new_object;
 324 }
 325 /* }}} */
 326 
 327 static inline zval *spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset) /* {{{ */
 328 {
 329         zend_long index;
 330 
 331         /* we have to return NULL on error here to avoid memleak because of
 332          * ZE duplicating uninitialized_zval_ptr */
 333         if (!offset) {
 334                 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
 335                 return NULL;
 336         }
 337 
 338         if (Z_TYPE_P(offset) != IS_LONG) {
 339                 index = spl_offset_convert_to_long(offset);
 340         } else {
 341                 index = Z_LVAL_P(offset);
 342         }
 343 
 344         if (index < 0 || intern->array == NULL || index >= intern->array->size) {
 345                 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
 346                 return NULL;
 347         } else if (Z_ISUNDEF(intern->array->elements[index])) {
 348                 return NULL;
 349         } else {
 350                 return &intern->array->elements[index];
 351         }
 352 }
 353 /* }}} */
 354 
 355 static zval *spl_fixedarray_object_read_dimension(zval *object, zval *offset, int type, zval *rv) /* {{{ */
 356 {
 357         spl_fixedarray_object *intern;
 358 
 359         intern = Z_SPLFIXEDARRAY_P(object);
 360 
 361         if (intern->fptr_offset_get) {
 362                 zval tmp;
 363                 if (!offset) {
 364                         ZVAL_UNDEF(&tmp);
 365                         offset = &tmp;
 366                 } else {
 367                         SEPARATE_ARG_IF_REF(offset);
 368                 }
 369                 zend_call_method_with_1_params(object, intern->std.ce, &intern->fptr_offset_get, "offsetGet", rv, offset);
 370                 zval_ptr_dtor(offset);
 371                 if (!Z_ISUNDEF_P(rv)) {
 372                         return rv;
 373                 }
 374                 return &EG(uninitialized_zval);
 375         }
 376 
 377         return spl_fixedarray_object_read_dimension_helper(intern, offset);
 378 }
 379 /* }}} */
 380 
 381 static inline void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *intern, zval *offset, zval *value) /* {{{ */
 382 {
 383         zend_long index;
 384 
 385         if (!offset) {
 386                 /* '$array[] = value' syntax is not supported */
 387                 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
 388                 return;
 389         }
 390 
 391         if (Z_TYPE_P(offset) != IS_LONG) {
 392                 index = spl_offset_convert_to_long(offset);
 393         } else {
 394                 index = Z_LVAL_P(offset);
 395         }
 396 
 397         if (index < 0 || intern->array == NULL || index >= intern->array->size) {
 398                 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
 399                 return;
 400         } else {
 401                 if (!Z_ISUNDEF(intern->array->elements[index])) {
 402                         zval_ptr_dtor(&(intern->array->elements[index]));
 403                 }
 404                 ZVAL_DEREF(value);
 405                 ZVAL_COPY(&intern->array->elements[index], value);
 406         }
 407 }
 408 /* }}} */
 409 
 410 static void spl_fixedarray_object_write_dimension(zval *object, zval *offset, zval *value) /* {{{ */
 411 {
 412         spl_fixedarray_object *intern;
 413 
 414         intern = Z_SPLFIXEDARRAY_P(object);
 415 
 416         if (intern->fptr_offset_set) {
 417                 zval tmp;
 418                 if (!offset) {
 419                         ZVAL_NULL(&tmp);
 420                         offset = &tmp;
 421                 } else {
 422                         SEPARATE_ARG_IF_REF(offset);
 423                 }
 424                 SEPARATE_ARG_IF_REF(value);
 425                 zend_call_method_with_2_params(object, intern->std.ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
 426                 zval_ptr_dtor(value);
 427                 zval_ptr_dtor(offset);
 428                 return;
 429         }
 430 
 431         spl_fixedarray_object_write_dimension_helper(intern, offset, value);
 432 }
 433 /* }}} */
 434 
 435 static inline void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *intern, zval *offset) /* {{{ */
 436 {
 437         zend_long index;
 438 
 439         if (Z_TYPE_P(offset) != IS_LONG) {
 440                 index = spl_offset_convert_to_long(offset);
 441         } else {
 442                 index = Z_LVAL_P(offset);
 443         }
 444 
 445         if (index < 0 || intern->array == NULL || index >= intern->array->size) {
 446                 zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
 447                 return;
 448         } else {
 449                 zval_ptr_dtor(&(intern->array->elements[index]));
 450                 ZVAL_UNDEF(&intern->array->elements[index]);
 451         }
 452 }
 453 /* }}} */
 454 
 455 static void spl_fixedarray_object_unset_dimension(zval *object, zval *offset) /* {{{ */
 456 {
 457         spl_fixedarray_object *intern;
 458 
 459         intern = Z_SPLFIXEDARRAY_P(object);
 460 
 461         if (intern->fptr_offset_del) {
 462                 SEPARATE_ARG_IF_REF(offset);
 463                 zend_call_method_with_1_params(object, intern->std.ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset);
 464                 zval_ptr_dtor(offset);
 465                 return;
 466         }
 467 
 468         spl_fixedarray_object_unset_dimension_helper(intern, offset);
 469 
 470 }
 471 /* }}} */
 472 
 473 static inline int spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *intern, zval *offset, int check_empty) /* {{{ */
 474 {
 475         zend_long index;
 476         int retval;
 477 
 478         if (Z_TYPE_P(offset) != IS_LONG) {
 479                 index = spl_offset_convert_to_long(offset);
 480         } else {
 481                 index = Z_LVAL_P(offset);
 482         }
 483 
 484         if (index < 0 || intern->array == NULL || index >= intern->array->size) {
 485                 retval = 0;
 486         } else {
 487                 if (Z_ISUNDEF(intern->array->elements[index])) {
 488                         retval = 0;
 489                 } else if (check_empty) {
 490                         if (zend_is_true(&intern->array->elements[index])) {
 491                                 retval = 1;
 492                         } else {
 493                                 retval = 0;
 494                         }
 495                 } else { /* != NULL and !check_empty */
 496                         retval = 1;
 497                 }
 498         }
 499 
 500         return retval;
 501 }
 502 /* }}} */
 503 
 504 static int spl_fixedarray_object_has_dimension(zval *object, zval *offset, int check_empty) /* {{{ */
 505 {
 506         spl_fixedarray_object *intern;
 507 
 508         intern = Z_SPLFIXEDARRAY_P(object);
 509 
 510         if (intern->fptr_offset_get) {
 511                 zval rv;
 512                 SEPARATE_ARG_IF_REF(offset);
 513                 zend_call_method_with_1_params(object, intern->std.ce, &intern->fptr_offset_has, "offsetExists", &rv, offset);
 514                 zval_ptr_dtor(offset);
 515                 if (!Z_ISUNDEF(rv)) {
 516                         zend_bool result = zend_is_true(&rv);
 517                         zval_ptr_dtor(&rv);
 518                         return result;
 519                 }
 520                 return 0;
 521         }
 522 
 523         return spl_fixedarray_object_has_dimension_helper(intern, offset, check_empty);
 524 }
 525 /* }}} */
 526 
 527 static int spl_fixedarray_object_count_elements(zval *object, zend_long *count) /* {{{ */
 528 {
 529         spl_fixedarray_object *intern;
 530 
 531         intern = Z_SPLFIXEDARRAY_P(object);
 532         if (intern->fptr_count) {
 533                 zval rv;
 534                 zend_call_method_with_0_params(object, intern->std.ce, &intern->fptr_count, "count", &rv);
 535                 if (!Z_ISUNDEF(rv)) {
 536                         *count = zval_get_long(&rv);
 537                         zval_ptr_dtor(&rv);
 538                         return SUCCESS;
 539                 }
 540         } else if (intern->array) {
 541                 *count = intern->array->size;
 542                 return SUCCESS;
 543         }
 544 
 545         *count = 0;
 546         return SUCCESS;
 547 }
 548 /* }}} */
 549 
 550 /* {{{ proto void SplFixedArray::__construct([int size])
 551 */
 552 SPL_METHOD(SplFixedArray, __construct)
 553 {
 554         zval *object = getThis();
 555         spl_fixedarray_object *intern;
 556         zend_long size = 0;
 557 
 558         if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|l", &size) == FAILURE) {
 559                 return;
 560         }
 561 
 562         if (size < 0) {
 563                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array size cannot be less than zero");
 564                 return;
 565         }
 566 
 567         intern = Z_SPLFIXEDARRAY_P(object);
 568 
 569         if (intern->array) {
 570                 /* called __construct() twice, bail out */
 571                 return;
 572         }
 573 
 574         intern->array = emalloc(sizeof(spl_fixedarray));
 575         spl_fixedarray_init(intern->array, size);
 576 }
 577 /* }}} */
 578 
 579 /* {{{ proto void SplFixedArray::__wakeup()
 580 */
 581 SPL_METHOD(SplFixedArray, __wakeup)
 582 {
 583         spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
 584         HashTable *intern_ht = zend_std_get_properties(getThis());
 585         zval *data;
 586 
 587         if (zend_parse_parameters_none() == FAILURE) {
 588                 return;
 589         }
 590 
 591         if (!intern->array) {
 592                 int index = 0;
 593                 int size = zend_hash_num_elements(intern_ht);
 594 
 595                 intern->array = emalloc(sizeof(spl_fixedarray));
 596                 spl_fixedarray_init(intern->array, size);
 597 
 598                 ZEND_HASH_FOREACH_VAL(intern_ht, data) {
 599                         if (Z_REFCOUNTED_P(data)) {
 600                                 Z_ADDREF_P(data);
 601                         }
 602                         ZVAL_COPY_VALUE(&intern->array->elements[index], data);
 603                         index++;
 604                 } ZEND_HASH_FOREACH_END();
 605 
 606                 /* Remove the unserialised properties, since we now have the elements
 607                  * within the spl_fixedarray_object structure. */
 608                 zend_hash_clean(intern_ht);
 609         }
 610 }
 611 /* }}} */
 612 
 613 /* {{{ proto int SplFixedArray::count(void)
 614 */
 615 SPL_METHOD(SplFixedArray, count)
 616 {
 617         zval *object = getThis();
 618         spl_fixedarray_object *intern;
 619 
 620         if (zend_parse_parameters_none() == FAILURE) {
 621                 return;
 622         }
 623 
 624         intern = Z_SPLFIXEDARRAY_P(object);
 625         if (intern->array) {
 626                 RETURN_LONG(intern->array->size);
 627         }
 628         RETURN_LONG(0);
 629 }
 630 /* }}} */
 631 
 632 /* {{{ proto object SplFixedArray::toArray()
 633 */
 634 SPL_METHOD(SplFixedArray, toArray)
 635 {
 636         spl_fixedarray_object *intern;
 637 
 638         if (zend_parse_parameters_none() == FAILURE) {
 639                 return;
 640         }
 641 
 642         intern = Z_SPLFIXEDARRAY_P(getThis());
 643 
 644         array_init(return_value);
 645         if (intern->array) {
 646                 int i = 0;
 647                 for (; i < intern->array->size; i++) {
 648                         if (!Z_ISUNDEF(intern->array->elements[i])) {
 649                                 zend_hash_index_update(Z_ARRVAL_P(return_value), i, &intern->array->elements[i]);
 650                                 if (Z_REFCOUNTED(intern->array->elements[i])) {
 651                                         Z_ADDREF(intern->array->elements[i]);
 652                                 }
 653                         } else {
 654                                 zend_hash_index_update(Z_ARRVAL_P(return_value), i, &EG(uninitialized_zval));
 655                         }
 656                 }
 657         }
 658 }
 659 /* }}} */
 660 
 661 /* {{{ proto object SplFixedArray::fromArray(array data[, bool save_indexes])
 662 */
 663 SPL_METHOD(SplFixedArray, fromArray)
 664 {
 665         zval *data;
 666         spl_fixedarray *array;
 667         spl_fixedarray_object *intern;
 668         int num;
 669         zend_bool save_indexes = 1;
 670 
 671         if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &data, &save_indexes) == FAILURE) {
 672                 return;
 673         }
 674 
 675         array = ecalloc(1, sizeof(spl_fixedarray));
 676         num = zend_hash_num_elements(Z_ARRVAL_P(data));
 677 
 678         if (num > 0 && save_indexes) {
 679                 zval *element;
 680                 zend_string *str_index;
 681                 zend_ulong num_index, max_index = 0;
 682                 zend_long tmp;
 683 
 684                 ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(data), num_index, str_index) {
 685                         if (str_index != NULL || (zend_long)num_index < 0) {
 686                                 efree(array);
 687                                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array must contain only positive integer keys");
 688                                 return;
 689                         }
 690 
 691                         if (num_index > max_index) {
 692                                 max_index = num_index;
 693                         }
 694                 } ZEND_HASH_FOREACH_END();
 695 
 696                 tmp = max_index + 1;
 697                 if (tmp <= 0) {
 698                         efree(array);
 699                         zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "integer overflow detected");
 700                         return;
 701                 }
 702                 spl_fixedarray_init(array, tmp);
 703 
 704                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(data), num_index, str_index, element) {
 705                         ZVAL_DEREF(element);
 706                         ZVAL_COPY(&array->elements[num_index], element);
 707                 } ZEND_HASH_FOREACH_END();
 708 
 709         } else if (num > 0 && !save_indexes) {
 710                 zval *element;
 711                 zend_long i = 0;
 712 
 713                 spl_fixedarray_init(array, num);
 714 
 715                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(data), element) {
 716                         ZVAL_DEREF(element);
 717                         ZVAL_COPY(&array->elements[i], element);
 718                         i++;
 719                 } ZEND_HASH_FOREACH_END();
 720         } else {
 721                 spl_fixedarray_init(array, 0);
 722         }
 723 
 724         object_init_ex(return_value, spl_ce_SplFixedArray);
 725 
 726         intern = Z_SPLFIXEDARRAY_P(return_value);
 727         intern->array = array;
 728 }
 729 /* }}} */
 730 
 731 /* {{{ proto int SplFixedArray::getSize(void)
 732 */
 733 SPL_METHOD(SplFixedArray, getSize)
 734 {
 735         zval *object = getThis();
 736         spl_fixedarray_object *intern;
 737 
 738         if (zend_parse_parameters_none() == FAILURE) {
 739                 return;
 740         }
 741 
 742         intern = Z_SPLFIXEDARRAY_P(object);
 743         if (intern->array) {
 744                 RETURN_LONG(intern->array->size);
 745         }
 746         RETURN_LONG(0);
 747 }
 748 /* }}} */
 749 
 750 /* {{{ proto bool SplFixedArray::setSize(int size)
 751 */
 752 SPL_METHOD(SplFixedArray, setSize)
 753 {
 754         zval *object = getThis();
 755         spl_fixedarray_object *intern;
 756         zend_long size;
 757 
 758         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &size) == FAILURE) {
 759                 return;
 760         }
 761 
 762         if (size < 0) {
 763                 zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0, "array size cannot be less than zero");
 764                 return;
 765         }
 766 
 767         intern = Z_SPLFIXEDARRAY_P(object);
 768         if (!intern->array) {
 769                 intern->array = ecalloc(1, sizeof(spl_fixedarray));
 770         }
 771 
 772         spl_fixedarray_resize(intern->array, size);
 773         RETURN_TRUE;
 774 }
 775 /* }}} */
 776 
 777 /* {{{ proto bool SplFixedArray::offsetExists(mixed $index)
 778  Returns whether the requested $index exists. */
 779 SPL_METHOD(SplFixedArray, offsetExists)
 780 {
 781         zval                  *zindex;
 782         spl_fixedarray_object  *intern;
 783 
 784         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) {
 785                 return;
 786         }
 787 
 788         intern = Z_SPLFIXEDARRAY_P(getThis());
 789 
 790         RETURN_BOOL(spl_fixedarray_object_has_dimension_helper(intern, zindex, 0));
 791 } /* }}} */
 792 
 793 /* {{{ proto mixed SplFixedArray::offsetGet(mixed $index)
 794  Returns the value at the specified $index. */
 795 SPL_METHOD(SplFixedArray, offsetGet)
 796 {
 797         zval *zindex, *value;
 798         spl_fixedarray_object  *intern;
 799 
 800         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) {
 801                 return;
 802         }
 803 
 804         intern = Z_SPLFIXEDARRAY_P(getThis());
 805         value = spl_fixedarray_object_read_dimension_helper(intern, zindex);
 806 
 807         if (value) {
 808                 ZVAL_DEREF(value);
 809                 ZVAL_COPY(return_value, value);
 810         } else {
 811                 RETURN_NULL();
 812         }
 813 } /* }}} */
 814 
 815 /* {{{ proto void SplFixedArray::offsetSet(mixed $index, mixed $newval)
 816  Sets the value at the specified $index to $newval. */
 817 SPL_METHOD(SplFixedArray, offsetSet)
 818 {
 819         zval                  *zindex, *value;
 820         spl_fixedarray_object  *intern;
 821 
 822         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zindex, &value) == FAILURE) {
 823                 return;
 824         }
 825 
 826         intern = Z_SPLFIXEDARRAY_P(getThis());
 827         spl_fixedarray_object_write_dimension_helper(intern, zindex, value);
 828 
 829 } /* }}} */
 830 
 831 /* {{{ proto void SplFixedArray::offsetUnset(mixed $index)
 832  Unsets the value at the specified $index. */
 833 SPL_METHOD(SplFixedArray, offsetUnset)
 834 {
 835         zval                  *zindex;
 836         spl_fixedarray_object  *intern;
 837 
 838         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zindex) == FAILURE) {
 839                 return;
 840         }
 841 
 842         intern = Z_SPLFIXEDARRAY_P(getThis());
 843         spl_fixedarray_object_unset_dimension_helper(intern, zindex);
 844 
 845 } /* }}} */
 846 
 847 static void spl_fixedarray_it_dtor(zend_object_iterator *iter) /* {{{ */
 848 {
 849         spl_fixedarray_it  *iterator = (spl_fixedarray_it *)iter;
 850 
 851         zend_user_it_invalidate_current(iter);
 852         zval_ptr_dtor(&iterator->intern.it.data);
 853 }
 854 /* }}} */
 855 
 856 static void spl_fixedarray_it_rewind(zend_object_iterator *iter) /* {{{ */
 857 {
 858         spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
 859 
 860         if (object->flags & SPL_FIXEDARRAY_OVERLOADED_REWIND) {
 861                 zend_user_it_rewind(iter);
 862         } else {
 863                 object->current = 0;
 864         }
 865 }
 866 /* }}} */
 867 
 868 static int spl_fixedarray_it_valid(zend_object_iterator *iter) /* {{{ */
 869 {
 870         spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
 871 
 872         if (object->flags & SPL_FIXEDARRAY_OVERLOADED_VALID) {
 873                 return zend_user_it_valid(iter);
 874         }
 875 
 876         if (object->current >= 0 && object->array && object->current < object->array->size) {
 877                 return SUCCESS;
 878         }
 879 
 880         return FAILURE;
 881 }
 882 /* }}} */
 883 
 884 static zval *spl_fixedarray_it_get_current_data(zend_object_iterator *iter) /* {{{ */
 885 {
 886         zval zindex;
 887         spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
 888 
 889         if (object->flags & SPL_FIXEDARRAY_OVERLOADED_CURRENT) {
 890                 return zend_user_it_get_current_data(iter);
 891         } else {
 892                 zval *data;
 893 
 894                 ZVAL_LONG(&zindex, object->current);
 895 
 896                 data = spl_fixedarray_object_read_dimension_helper(object, &zindex);
 897                 zval_ptr_dtor(&zindex);
 898 
 899                 if (data == NULL) {
 900                         data = &EG(uninitialized_zval);
 901                 }
 902                 return data;
 903         }
 904 }
 905 /* }}} */
 906 
 907 static void spl_fixedarray_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
 908 {
 909         spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
 910 
 911         if (object->flags & SPL_FIXEDARRAY_OVERLOADED_KEY) {
 912                 zend_user_it_get_current_key(iter, key);
 913         } else {
 914                 ZVAL_LONG(key, object->current);
 915         }
 916 }
 917 /* }}} */
 918 
 919 static void spl_fixedarray_it_move_forward(zend_object_iterator *iter) /* {{{ */
 920 {
 921         spl_fixedarray_object *object = Z_SPLFIXEDARRAY_P(&iter->data);
 922 
 923         if (object->flags & SPL_FIXEDARRAY_OVERLOADED_NEXT) {
 924                 zend_user_it_move_forward(iter);
 925         } else {
 926                 zend_user_it_invalidate_current(iter);
 927                 object->current++;
 928         }
 929 }
 930 /* }}} */
 931 
 932 /* {{{  proto int SplFixedArray::key()
 933    Return current array key */
 934 SPL_METHOD(SplFixedArray, key)
 935 {
 936         spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
 937 
 938         if (zend_parse_parameters_none() == FAILURE) {
 939                 return;
 940         }
 941 
 942         RETURN_LONG(intern->current);
 943 }
 944 /* }}} */
 945 
 946 /* {{{ proto void SplFixedArray::next()
 947    Move to next entry */
 948 SPL_METHOD(SplFixedArray, next)
 949 {
 950         spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
 951 
 952         if (zend_parse_parameters_none() == FAILURE) {
 953                 return;
 954         }
 955 
 956         intern->current++;
 957 }
 958 /* }}} */
 959 
 960 /* {{{ proto bool SplFixedArray::valid()
 961    Check whether the datastructure contains more entries */
 962 SPL_METHOD(SplFixedArray, valid)
 963 {
 964         spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
 965 
 966         if (zend_parse_parameters_none() == FAILURE) {
 967                 return;
 968         }
 969 
 970         RETURN_BOOL(intern->current >= 0 && intern->array && intern->current < intern->array->size);
 971 }
 972 /* }}} */
 973 
 974 /* {{{ proto void SplFixedArray::rewind()
 975    Rewind the datastructure back to the start */
 976 SPL_METHOD(SplFixedArray, rewind)
 977 {
 978         spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(getThis());
 979 
 980         if (zend_parse_parameters_none() == FAILURE) {
 981                 return;
 982         }
 983 
 984         intern->current = 0;
 985 }
 986 /* }}} */
 987 
 988 /* {{{ proto mixed|NULL SplFixedArray::current()
 989    Return current datastructure entry */
 990 SPL_METHOD(SplFixedArray, current)
 991 {
 992         zval zindex, *value;
 993         spl_fixedarray_object *intern  = Z_SPLFIXEDARRAY_P(getThis());
 994 
 995         if (zend_parse_parameters_none() == FAILURE) {
 996                 return;
 997         }
 998 
 999         ZVAL_LONG(&zindex, intern->current);
1000 
1001         value = spl_fixedarray_object_read_dimension_helper(intern, &zindex);
1002 
1003         zval_ptr_dtor(&zindex);
1004 
1005         if (value) {
1006                 ZVAL_DEREF(value);
1007                 ZVAL_COPY(return_value, value);
1008         } else {
1009                 RETURN_NULL();
1010         }
1011 }
1012 /* }}} */
1013 
1014 /* iterator handler table */
1015 zend_object_iterator_funcs spl_fixedarray_it_funcs = {
1016         spl_fixedarray_it_dtor,
1017         spl_fixedarray_it_valid,
1018         spl_fixedarray_it_get_current_data,
1019         spl_fixedarray_it_get_current_key,
1020         spl_fixedarray_it_move_forward,
1021         spl_fixedarray_it_rewind
1022 };
1023 
1024 zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
1025 {
1026         spl_fixedarray_it *iterator;
1027 
1028         if (by_ref) {
1029                 zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0);
1030                 return NULL;
1031         }
1032 
1033         iterator = emalloc(sizeof(spl_fixedarray_it));
1034 
1035         zend_iterator_init((zend_object_iterator*)iterator);
1036 
1037         ZVAL_COPY(&iterator->intern.it.data, object);
1038         iterator->intern.it.funcs = &spl_fixedarray_it_funcs;
1039         iterator->intern.ce = ce;
1040         ZVAL_UNDEF(&iterator->intern.value);
1041 
1042         return &iterator->intern.it;
1043 }
1044 /* }}} */
1045 
1046 ZEND_BEGIN_ARG_INFO_EX(arginfo_splfixedarray_construct, 0, 0, 0)
1047         ZEND_ARG_INFO(0, size)
1048 ZEND_END_ARG_INFO()
1049 
1050 ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetGet, 0, 0, 1)
1051         ZEND_ARG_INFO(0, index)
1052 ZEND_END_ARG_INFO()
1053 
1054 ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetSet, 0, 0, 2)
1055         ZEND_ARG_INFO(0, index)
1056         ZEND_ARG_INFO(0, newval)
1057 ZEND_END_ARG_INFO()
1058 
1059 ZEND_BEGIN_ARG_INFO(arginfo_fixedarray_setSize, 0)
1060         ZEND_ARG_INFO(0, value)
1061 ZEND_END_ARG_INFO()
1062 
1063 ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_fromArray, 0, 0, 1)
1064         ZEND_ARG_INFO(0, data)
1065         ZEND_ARG_INFO(0, save_indexes)
1066 ZEND_END_ARG_INFO()
1067 
1068 ZEND_BEGIN_ARG_INFO(arginfo_splfixedarray_void, 0)
1069 ZEND_END_ARG_INFO()
1070 
1071 static zend_function_entry spl_funcs_SplFixedArray[] = { /* {{{ */
1072         SPL_ME(SplFixedArray, __construct,     arginfo_splfixedarray_construct,ZEND_ACC_PUBLIC)
1073         SPL_ME(SplFixedArray, __wakeup,        arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1074         SPL_ME(SplFixedArray, count,           arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1075         SPL_ME(SplFixedArray, toArray,         arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1076         SPL_ME(SplFixedArray, fromArray,       arginfo_fixedarray_fromArray,   ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1077         SPL_ME(SplFixedArray, getSize,         arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1078         SPL_ME(SplFixedArray, setSize,         arginfo_fixedarray_setSize,     ZEND_ACC_PUBLIC)
1079         SPL_ME(SplFixedArray, offsetExists,    arginfo_fixedarray_offsetGet,   ZEND_ACC_PUBLIC)
1080         SPL_ME(SplFixedArray, offsetGet,       arginfo_fixedarray_offsetGet,   ZEND_ACC_PUBLIC)
1081         SPL_ME(SplFixedArray, offsetSet,       arginfo_fixedarray_offsetSet,   ZEND_ACC_PUBLIC)
1082         SPL_ME(SplFixedArray, offsetUnset,     arginfo_fixedarray_offsetGet,   ZEND_ACC_PUBLIC)
1083         SPL_ME(SplFixedArray, rewind,          arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1084         SPL_ME(SplFixedArray, current,         arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1085         SPL_ME(SplFixedArray, key,             arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1086         SPL_ME(SplFixedArray, next,            arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1087         SPL_ME(SplFixedArray, valid,           arginfo_splfixedarray_void,     ZEND_ACC_PUBLIC)
1088         PHP_FE_END
1089 };
1090 /* }}} */
1091 
1092 /* {{{ PHP_MINIT_FUNCTION */
1093 PHP_MINIT_FUNCTION(spl_fixedarray)
1094 {
1095         REGISTER_SPL_STD_CLASS_EX(SplFixedArray, spl_fixedarray_new, spl_funcs_SplFixedArray);
1096         memcpy(&spl_handler_SplFixedArray, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1097 
1098         spl_handler_SplFixedArray.offset          = XtOffsetOf(spl_fixedarray_object, std);
1099         spl_handler_SplFixedArray.clone_obj       = spl_fixedarray_object_clone;
1100         spl_handler_SplFixedArray.read_dimension  = spl_fixedarray_object_read_dimension;
1101         spl_handler_SplFixedArray.write_dimension = spl_fixedarray_object_write_dimension;
1102         spl_handler_SplFixedArray.unset_dimension = spl_fixedarray_object_unset_dimension;
1103         spl_handler_SplFixedArray.has_dimension   = spl_fixedarray_object_has_dimension;
1104         spl_handler_SplFixedArray.count_elements  = spl_fixedarray_object_count_elements;
1105         spl_handler_SplFixedArray.get_properties  = spl_fixedarray_object_get_properties;
1106         spl_handler_SplFixedArray.get_gc          = spl_fixedarray_object_get_gc;
1107         spl_handler_SplFixedArray.dtor_obj        = zend_objects_destroy_object;
1108         spl_handler_SplFixedArray.free_obj        = spl_fixedarray_object_free_storage;
1109 
1110         REGISTER_SPL_IMPLEMENTS(SplFixedArray, Iterator);
1111         REGISTER_SPL_IMPLEMENTS(SplFixedArray, ArrayAccess);
1112         REGISTER_SPL_IMPLEMENTS(SplFixedArray, Countable);
1113 
1114         spl_ce_SplFixedArray->get_iterator = spl_fixedarray_get_iterator;
1115 
1116         return SUCCESS;
1117 }
1118 /* }}} */
1119 
1120 
1121 /*
1122  * Local variables:
1123  * tab-width: 4
1124  * c-basic-offset: 4
1125  * End:
1126  * vim600: noet sw=4 ts=4 fdm=marker
1127  * vim<600: noet sw=4 ts=4
1128  */

/* [<][>][^][v][top][bottom][index][help] */