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