Annotation of embedaddon/php/ext/spl/spl_fixedarray.c, revision 1.1.1.1
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:
20: /* $Id: spl_fixedarray.c 321634 2012-01-01 13:15:04Z felipe $ */
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);
153: int i = 0;
154:
155: if (intern->array && !GC_G(gc_active)) {
156: int j = zend_hash_num_elements(intern->std.properties);
157:
158: for (i = 0; i < intern->array->size; i++) {
159: if (intern->array->elements[i]) {
160: zend_hash_index_update(intern->std.properties, i, (void *)&intern->array->elements[i], sizeof(zval *), NULL);
161: Z_ADDREF_P(intern->array->elements[i]);
162: } else {
163: zend_hash_index_update(intern->std.properties, i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL);
164: Z_ADDREF_P(EG(uninitialized_zval_ptr));
165: }
166: }
167: if (j > intern->array->size) {
168: for (i = intern->array->size; i < j; ++i) {
169: zend_hash_index_del(intern->std.properties, i);
170: }
171: }
172: }
173:
174: return intern->std.properties;
175: }
176: /* }}}} */
177:
178: static void spl_fixedarray_object_free_storage(void *object TSRMLS_DC) /* {{{ */
179: {
180: spl_fixedarray_object *intern = (spl_fixedarray_object *)object;
181: long i;
182:
183: if (intern->array) {
184: for (i = 0; i < intern->array->size; i++) {
185: if (intern->array->elements[i]) {
186: zval_ptr_dtor(&(intern->array->elements[i]));
187: }
188: }
189:
190: if (intern->array->size > 0 && intern->array->elements) {
191: efree(intern->array->elements);
192: }
193: efree(intern->array);
194: }
195:
196: zend_object_std_dtor(&intern->std TSRMLS_CC);
197: zval_ptr_dtor(&intern->retval);
198:
199: efree(object);
200: }
201: /* }}} */
202:
203: zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
204:
205: 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) /* {{{ */
206: {
207: zend_object_value retval;
208: spl_fixedarray_object *intern;
209: zval *tmp;
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);
218: zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
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: spl_fixedarray_object *intern;
606: zval *ret, *tmp;
607: HashTable *ret_ht, *obj_ht;
608:
609: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) {
610: return;
611: }
612:
613: intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
614:
615: ALLOC_HASHTABLE(ret_ht);
616: zend_hash_init(ret_ht, 0, NULL, ZVAL_PTR_DTOR, 0);
617: ALLOC_INIT_ZVAL(ret);
618: Z_TYPE_P(ret) = IS_ARRAY;
619: obj_ht = spl_fixedarray_object_get_properties(getThis() TSRMLS_CC);
620: zend_hash_copy(ret_ht, obj_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
621: Z_ARRVAL_P(ret) = ret_ht;
622:
623: RETURN_ZVAL(ret, 1, 1);
624: }
625: /* }}} */
626:
627: /* {{{ proto object SplFixedArray::fromArray(array data[, bool save_indexes])
628: */
629: SPL_METHOD(SplFixedArray, fromArray)
630: {
631: zval *data;
632: spl_fixedarray *array;
633: spl_fixedarray_object *intern;
634: int num;
635: zend_bool save_indexes = 1;
636:
637: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &data, &save_indexes)) {
638: return;
639: }
640:
641: array = ecalloc(1, sizeof(*array));
642: num = zend_hash_num_elements(Z_ARRVAL_P(data));
643:
644: if (num > 0 && save_indexes) {
645: zval **element, *value;
646: char *str_index;
647: ulong num_index, max_index = 0;
648: long tmp;
649:
650: for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
651: zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
652: zend_hash_move_forward(Z_ARRVAL_P(data))
653: ) {
654: if (zend_hash_get_current_key(Z_ARRVAL_P(data), &str_index, &num_index, 0) != HASH_KEY_IS_LONG || (long)num_index < 0) {
655: efree(array);
656: zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array must contain only positive integer keys");
657: return;
658: }
659:
660: if (num_index > max_index) {
661: max_index = num_index;
662: }
663: }
664:
665: tmp = max_index + 1;
666: if (tmp <= 0) {
667: efree(array);
668: zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "integer overflow detected");
669: return;
670: }
671: spl_fixedarray_init(array, tmp TSRMLS_CC);
672:
673: for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
674: zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
675: zend_hash_move_forward(Z_ARRVAL_P(data))
676: ) {
677:
678: zend_hash_get_current_key(Z_ARRVAL_P(data), &str_index, &num_index, 0);
679: value = *element;
680:
681: SEPARATE_ARG_IF_REF(value);
682: array->elements[num_index] = value;
683: }
684:
685: } else if (num > 0 && !save_indexes) {
686: zval **element, *value;
687: long i = 0;
688:
689: spl_fixedarray_init(array, num TSRMLS_CC);
690:
691: for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data));
692: zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS;
693: zend_hash_move_forward(Z_ARRVAL_P(data))
694: ) {
695:
696: value = *element;
697:
698: SEPARATE_ARG_IF_REF(value);
699: array->elements[i] = value;
700: i++;
701: }
702: } else {
703: spl_fixedarray_init(array, 0 TSRMLS_CC);
704: }
705:
706: object_init_ex(return_value, spl_ce_SplFixedArray);
707: Z_TYPE_P(return_value) = IS_OBJECT;
708:
709: intern = (spl_fixedarray_object *)zend_object_store_get_object(return_value TSRMLS_CC);
710: intern->array = array;
711: }
712: /* }}} */
713:
714: /* {{{ proto int SplFixedArray::getSize(void)
715: */
716: SPL_METHOD(SplFixedArray, getSize)
717: {
718: zval *object = getThis();
719: spl_fixedarray_object *intern;
720:
721: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) {
722: return;
723: }
724:
725: intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
726: if (intern->array) {
727: RETURN_LONG(intern->array->size);
728: }
729: RETURN_LONG(0);
730: }
731: /* }}} */
732:
733: /* {{{ proto bool SplFixedArray::setSize(int size)
734: */
735: SPL_METHOD(SplFixedArray, setSize)
736: {
737: zval *object = getThis();
738: spl_fixedarray_object *intern;
739: long size;
740:
741: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size)) {
742: return;
743: }
744:
745: if (size < 0) {
746: zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero");
747: return;
748: }
749:
750: intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC);
751: if (!intern->array) {
752: intern->array = ecalloc(1, sizeof(spl_fixedarray));
753: }
754:
755: spl_fixedarray_resize(intern->array, size TSRMLS_CC);
756: RETURN_TRUE;
757: }
758: /* }}} */
759:
760: /* {{{ proto bool SplFixedArray::offsetExists(mixed $index) U
761: Returns whether the requested $index exists. */
762: SPL_METHOD(SplFixedArray, offsetExists)
763: {
764: zval *zindex;
765: spl_fixedarray_object *intern;
766:
767: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
768: return;
769: }
770:
771: intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
772:
773: RETURN_BOOL(spl_fixedarray_object_has_dimension_helper(intern, zindex, 0 TSRMLS_CC));
774: } /* }}} */
775:
776: /* {{{ proto mixed SplFixedArray::offsetGet(mixed $index) U
777: Returns the value at the specified $index. */
778: SPL_METHOD(SplFixedArray, offsetGet)
779: {
780: zval *zindex, **value_pp;
781: spl_fixedarray_object *intern;
782:
783: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
784: return;
785: }
786:
787: intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
788: value_pp = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
789:
790: if (value_pp) {
791: RETURN_ZVAL(*value_pp, 1, 0);
792: }
793: RETURN_NULL();
794: } /* }}} */
795:
796: /* {{{ proto void SplFixedArray::offsetSet(mixed $index, mixed $newval) U
797: Sets the value at the specified $index to $newval. */
798: SPL_METHOD(SplFixedArray, offsetSet)
799: {
800: zval *zindex, *value;
801: spl_fixedarray_object *intern;
802:
803: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) {
804: return;
805: }
806:
807: intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
808: spl_fixedarray_object_write_dimension_helper(intern, zindex, value TSRMLS_CC);
809:
810: } /* }}} */
811:
812: /* {{{ proto void SplFixedArray::offsetUnset(mixed $index) U
813: Unsets the value at the specified $index. */
814: SPL_METHOD(SplFixedArray, offsetUnset)
815: {
816: zval *zindex;
817: spl_fixedarray_object *intern;
818:
819: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) {
820: return;
821: }
822:
823: intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC);
824: spl_fixedarray_object_unset_dimension_helper(intern, zindex TSRMLS_CC);
825:
826: } /* }}} */
827:
828: static void spl_fixedarray_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
829: {
830: spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
831:
832: zend_user_it_invalidate_current(iter TSRMLS_CC);
833: zval_ptr_dtor((zval**)&iterator->intern.it.data);
834:
835: efree(iterator);
836: }
837: /* }}} */
838:
839: static void spl_fixedarray_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
840: {
841: spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
842: spl_fixedarray_object *intern = iterator->object;
843:
844: if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_REWIND) {
845: zend_user_it_rewind(iter TSRMLS_CC);
846: } else {
847: iterator->object->current = 0;
848: }
849: }
850: /* }}} */
851:
852: static int spl_fixedarray_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
853: {
854: spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
855: spl_fixedarray_object *intern = iterator->object;
856:
857: if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_VALID) {
858: return zend_user_it_valid(iter TSRMLS_CC);
859: }
860:
861: if (iterator->object->current >= 0 && iterator->object->array && iterator->object->current < iterator->object->array->size) {
862: return SUCCESS;
863: }
864:
865: return FAILURE;
866: }
867: /* }}} */
868:
869: static void spl_fixedarray_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
870: {
871: zval *zindex;
872: spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
873: spl_fixedarray_object *intern = iterator->object;
874:
875: if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_CURRENT) {
876: zend_user_it_get_current_data(iter, data TSRMLS_CC);
877: } else {
878: ALLOC_INIT_ZVAL(zindex);
879: ZVAL_LONG(zindex, iterator->object->current);
880:
881: *data = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
882:
883: if (*data == NULL) {
884: *data = &EG(uninitialized_zval_ptr);
885: }
886:
887: zval_ptr_dtor(&zindex);
888: }
889: }
890: /* }}} */
891:
892: static int spl_fixedarray_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
893: {
894: spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
895: spl_fixedarray_object *intern = iterator->object;
896:
897: if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_KEY) {
898: return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
899: } else {
900: *int_key = (ulong) iterator->object->current;
901: return HASH_KEY_IS_LONG;
902: }
903:
904: }
905: /* }}} */
906:
907: static void spl_fixedarray_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
908: {
909: spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter;
910: spl_fixedarray_object *intern = iterator->object;
911:
912: if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_NEXT) {
913: zend_user_it_move_forward(iter TSRMLS_CC);
914: } else {
915: zend_user_it_invalidate_current(iter TSRMLS_CC);
916: iterator->object->current++;
917: }
918: }
919: /* }}} */
920:
921: /* {{{ proto int SplFixedArray::key() U
922: Return current array key */
923: SPL_METHOD(SplFixedArray, key)
924: {
925: spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
926:
927: if (zend_parse_parameters_none() == FAILURE) {
928: return;
929: }
930:
931: RETURN_LONG(intern->current);
932: }
933: /* }}} */
934:
935: /* {{{ proto void SplFixedArray::next() U
936: Move to next entry */
937: SPL_METHOD(SplFixedArray, next)
938: {
939: spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
940:
941: if (zend_parse_parameters_none() == FAILURE) {
942: return;
943: }
944:
945: intern->current++;
946: }
947: /* }}} */
948:
949: /* {{{ proto bool SplFixedArray::valid() U
950: Check whether the datastructure contains more entries */
951: SPL_METHOD(SplFixedArray, valid)
952: {
953: spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
954:
955: if (zend_parse_parameters_none() == FAILURE) {
956: return;
957: }
958:
959: RETURN_BOOL(intern->current >= 0 && intern->array && intern->current < intern->array->size);
960: }
961: /* }}} */
962:
963: /* {{{ proto void SplFixedArray::rewind() U
964: Rewind the datastructure back to the start */
965: SPL_METHOD(SplFixedArray, rewind)
966: {
967: spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
968:
969: if (zend_parse_parameters_none() == FAILURE) {
970: return;
971: }
972:
973: intern->current = 0;
974: }
975: /* }}} */
976:
977: /* {{{ proto mixed|NULL SplFixedArray::current() U
978: Return current datastructure entry */
979: SPL_METHOD(SplFixedArray, current)
980: {
981: zval *zindex, **value_pp;
982: spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
983:
984: if (zend_parse_parameters_none() == FAILURE) {
985: return;
986: }
987:
988: ALLOC_INIT_ZVAL(zindex);
989: ZVAL_LONG(zindex, intern->current);
990:
991: value_pp = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC);
992:
993: zval_ptr_dtor(&zindex);
994:
995: if (value_pp) {
996: RETURN_ZVAL(*value_pp, 1, 0);
997: }
998: RETURN_NULL();
999: }
1000: /* }}} */
1001:
1002: /* iterator handler table */
1003: zend_object_iterator_funcs spl_fixedarray_it_funcs = {
1004: spl_fixedarray_it_dtor,
1005: spl_fixedarray_it_valid,
1006: spl_fixedarray_it_get_current_data,
1007: spl_fixedarray_it_get_current_key,
1008: spl_fixedarray_it_move_forward,
1009: spl_fixedarray_it_rewind
1010: };
1011:
1012: zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
1013: {
1014: spl_fixedarray_it *iterator;
1015: spl_fixedarray_object *fixedarray_object = (spl_fixedarray_object*)zend_object_store_get_object(object TSRMLS_CC);
1016:
1017: if (by_ref) {
1018: zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC);
1019: return NULL;
1020: }
1021:
1022: Z_ADDREF_P(object);
1023:
1024: iterator = emalloc(sizeof(spl_fixedarray_it));
1025: iterator->intern.it.data = (void*)object;
1026: iterator->intern.it.funcs = &spl_fixedarray_it_funcs;
1027: iterator->intern.ce = ce;
1028: iterator->intern.value = NULL;
1029: iterator->object = fixedarray_object;
1030:
1031: return (zend_object_iterator*)iterator;
1032: }
1033: /* }}} */
1034:
1035: ZEND_BEGIN_ARG_INFO_EX(arginfo_splfixedarray_construct, 0, 0, 0)
1036: ZEND_ARG_INFO(0, size)
1037: ZEND_END_ARG_INFO()
1038:
1039: ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetGet, 0, 0, 1)
1040: ZEND_ARG_INFO(0, index)
1041: ZEND_END_ARG_INFO()
1042:
1043: ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetSet, 0, 0, 2)
1044: ZEND_ARG_INFO(0, index)
1045: ZEND_ARG_INFO(0, newval)
1046: ZEND_END_ARG_INFO()
1047:
1048: ZEND_BEGIN_ARG_INFO(arginfo_fixedarray_setSize, 0)
1049: ZEND_ARG_INFO(0, value)
1050: ZEND_END_ARG_INFO()
1051:
1052: ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_fromArray, 0, 0, 1)
1053: ZEND_ARG_INFO(0, data)
1054: ZEND_ARG_INFO(0, save_indexes)
1055: ZEND_END_ARG_INFO()
1056:
1057: ZEND_BEGIN_ARG_INFO(arginfo_splfixedarray_void, 0)
1058: ZEND_END_ARG_INFO()
1059:
1060: static zend_function_entry spl_funcs_SplFixedArray[] = { /* {{{ */
1061: SPL_ME(SplFixedArray, __construct, arginfo_splfixedarray_construct,ZEND_ACC_PUBLIC)
1062: SPL_ME(SplFixedArray, count, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1063: SPL_ME(SplFixedArray, toArray, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1064: SPL_ME(SplFixedArray, fromArray, arginfo_fixedarray_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1065: SPL_ME(SplFixedArray, getSize, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1066: SPL_ME(SplFixedArray, setSize, arginfo_fixedarray_setSize, ZEND_ACC_PUBLIC)
1067: SPL_ME(SplFixedArray, offsetExists, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1068: SPL_ME(SplFixedArray, offsetGet, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1069: SPL_ME(SplFixedArray, offsetSet, arginfo_fixedarray_offsetSet, ZEND_ACC_PUBLIC)
1070: SPL_ME(SplFixedArray, offsetUnset, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC)
1071: SPL_ME(SplFixedArray, rewind, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1072: SPL_ME(SplFixedArray, current, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1073: SPL_ME(SplFixedArray, key, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1074: SPL_ME(SplFixedArray, next, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1075: SPL_ME(SplFixedArray, valid, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC)
1076: PHP_FE_END
1077: };
1078: /* }}} */
1079:
1080: /* {{{ PHP_MINIT_FUNCTION */
1081: PHP_MINIT_FUNCTION(spl_fixedarray)
1082: {
1083: REGISTER_SPL_STD_CLASS_EX(SplFixedArray, spl_fixedarray_new, spl_funcs_SplFixedArray);
1084: memcpy(&spl_handler_SplFixedArray, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1085:
1086: spl_handler_SplFixedArray.clone_obj = spl_fixedarray_object_clone;
1087: spl_handler_SplFixedArray.read_dimension = spl_fixedarray_object_read_dimension;
1088: spl_handler_SplFixedArray.write_dimension = spl_fixedarray_object_write_dimension;
1089: spl_handler_SplFixedArray.unset_dimension = spl_fixedarray_object_unset_dimension;
1090: spl_handler_SplFixedArray.has_dimension = spl_fixedarray_object_has_dimension;
1091: spl_handler_SplFixedArray.count_elements = spl_fixedarray_object_count_elements;
1092: spl_handler_SplFixedArray.get_properties = spl_fixedarray_object_get_properties;
1093:
1094: REGISTER_SPL_IMPLEMENTS(SplFixedArray, Iterator);
1095: REGISTER_SPL_IMPLEMENTS(SplFixedArray, ArrayAccess);
1096: REGISTER_SPL_IMPLEMENTS(SplFixedArray, Countable);
1097:
1098: spl_ce_SplFixedArray->get_iterator = spl_fixedarray_get_iterator;
1099:
1100: return SUCCESS;
1101: }
1102: /* }}} */
1103:
1104:
1105: /*
1106: * Local variables:
1107: * tab-width: 4
1108: * c-basic-offset: 4
1109: * End:
1110: * vim600: noet sw=4 ts=4 fdm=marker
1111: * vim<600: noet sw=4 ts=4
1112: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>