@@ -3026,6 +3026,276 @@ PHP_FUNCTION(iterator_to_array)
3026
3026
spl_iterator_apply (obj , use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply , (void * )return_value );
3027
3027
} /* }}} */
3028
3028
3029
+ typedef struct {
3030
+ /* To distinguish betwseen arrays and iterator objects we use the fact that UINT32_MAX
3031
+ * is not a possible array hash position index. */
3032
+ HashPosition hash_position_or_tag ;
3033
+ union {
3034
+ zend_array * array ;
3035
+ zend_object_iterator * obj_iter ;
3036
+ };
3037
+ } spl_zip_iterator_entry ;
3038
+
3039
+ typedef struct {
3040
+ zend_object_iterator intern ;
3041
+ spl_zip_iterator_entry * iterators ;
3042
+ zval key_array ;
3043
+ uint32_t iterator_count ;
3044
+ } spl_zip_iterator ;
3045
+
3046
+ static zend_always_inline bool spl_zip_iterator_is_obj_entry (const spl_zip_iterator_entry * entry )
3047
+ {
3048
+ return entry -> hash_position_or_tag == UINT32_MAX ;
3049
+ }
3050
+
3051
+ static void spl_iterator_zip_dtor (zend_object_iterator * iter )
3052
+ {
3053
+ spl_zip_iterator * zip_iterator = (spl_zip_iterator * ) iter ;
3054
+ for (uint32_t i = 0 ; i < zip_iterator -> iterator_count ; i ++ ) {
3055
+ spl_zip_iterator_entry * current = & zip_iterator -> iterators [i ];
3056
+ if (spl_zip_iterator_is_obj_entry (current )) {
3057
+ zend_iterator_dtor (current -> obj_iter );
3058
+ } else {
3059
+ zend_array_release (current -> array );
3060
+ }
3061
+ }
3062
+ zval_ptr_dtor (& iter -> data );
3063
+ efree (zip_iterator -> iterators );
3064
+ }
3065
+
3066
+ static zend_result spl_iterator_zip_valid (zend_object_iterator * iter )
3067
+ {
3068
+ spl_zip_iterator * zip_iterator = (spl_zip_iterator * ) iter ;
3069
+
3070
+ uint32_t i = 0 ;
3071
+ for (; i < zip_iterator -> iterator_count ; i ++ ) {
3072
+ spl_zip_iterator_entry * current = & zip_iterator -> iterators [i ];
3073
+ if (spl_zip_iterator_is_obj_entry (current )) {
3074
+ if (current -> obj_iter -> funcs -> valid (current -> obj_iter ) != SUCCESS ) {
3075
+ return FAILURE ;
3076
+ }
3077
+ } else {
3078
+ current -> hash_position_or_tag = zend_hash_get_current_pos_ex (current -> array , current -> hash_position_or_tag );
3079
+ if (current -> hash_position_or_tag >= current -> array -> nNumUsed ) {
3080
+ return FAILURE ;
3081
+ }
3082
+ }
3083
+ }
3084
+
3085
+ return i > 0 ? SUCCESS : FAILURE ;
3086
+ }
3087
+
3088
+ /* Invariant: returned array is packed and has all UNDEF elements. */
3089
+ static zend_array * spl_iterator_zip_reset_array (spl_zip_iterator * zip_iterator , zval * array_zv )
3090
+ {
3091
+ /* Reuse array if it's RC1 */
3092
+ if (!Z_ISUNDEF_P (array_zv ) && Z_REFCOUNT_P (array_zv ) == 1 ) {
3093
+ zend_array * array = Z_ARR_P (array_zv );
3094
+ if (HT_IS_PACKED (array )
3095
+ && array -> nNumUsed == zip_iterator -> iterator_count
3096
+ && array -> nNumOfElements == zip_iterator -> iterator_count ) {
3097
+ array -> nNextFreeElement = zip_iterator -> iterator_count ;
3098
+ for (uint32_t i = 0 ; i < zip_iterator -> iterator_count ; i ++ ) {
3099
+ zval_ptr_dtor (& array -> arPacked [i ]);
3100
+ ZVAL_UNDEF (& array -> arPacked [i ]);
3101
+ }
3102
+ return array ;
3103
+ }
3104
+ }
3105
+
3106
+ zval_ptr_dtor (array_zv );
3107
+
3108
+ /* Create optimized packed array */
3109
+ zend_array * array = zend_new_array (zip_iterator -> iterator_count );
3110
+ zend_hash_real_init_packed (array );
3111
+ array -> nNumUsed = array -> nNumOfElements = array -> nNextFreeElement = zip_iterator -> iterator_count ;
3112
+ ZVAL_ARR (array_zv , array );
3113
+ return array ;
3114
+ }
3115
+
3116
+ void spl_iterator_zip_get_current_key (zend_object_iterator * iter , zval * key )
3117
+ {
3118
+ spl_zip_iterator * zip_iterator = (spl_zip_iterator * ) iter ;
3119
+
3120
+ zend_array * array = spl_iterator_zip_reset_array (zip_iterator , & zip_iterator -> key_array );
3121
+
3122
+ for (uint32_t i = 0 ; i < zip_iterator -> iterator_count ; i ++ ) {
3123
+ spl_zip_iterator_entry * current = & zip_iterator -> iterators [i ];
3124
+ if (spl_zip_iterator_is_obj_entry (current )) {
3125
+ current -> obj_iter -> funcs -> get_current_key (current -> obj_iter , & array -> arPacked [i ]);
3126
+ if (UNEXPECTED (EG (exception ))) {
3127
+ ZVAL_NULL (key );
3128
+ return ;
3129
+ }
3130
+ } else {
3131
+ zend_hash_get_current_key_zval_ex (current -> array , & array -> arPacked [i ], & current -> hash_position_or_tag );
3132
+ }
3133
+ }
3134
+
3135
+ ZVAL_COPY (key , & zip_iterator -> key_array );
3136
+ }
3137
+
3138
+ zval * spl_iterator_zip_get_current_data (zend_object_iterator * iter )
3139
+ {
3140
+ spl_zip_iterator * zip_iterator = (spl_zip_iterator * ) iter ;
3141
+
3142
+ zend_array * array = spl_iterator_zip_reset_array (zip_iterator , & zip_iterator -> intern .data );
3143
+
3144
+ for (uint32_t i = 0 ; i < zip_iterator -> iterator_count ; i ++ ) {
3145
+ spl_zip_iterator_entry * current = & zip_iterator -> iterators [i ];
3146
+ zval * data ;
3147
+ if (spl_zip_iterator_is_obj_entry (current )) {
3148
+ data = current -> obj_iter -> funcs -> get_current_data (current -> obj_iter );
3149
+ } else {
3150
+ data = zend_hash_get_current_data_ex (current -> array , & current -> hash_position_or_tag );
3151
+ }
3152
+ if (UNEXPECTED (data == NULL )) {
3153
+ for (uint32_t j = 0 ; j < i ; j ++ ) {
3154
+ zval_ptr_dtor (& array -> arPacked [j ]);
3155
+ ZVAL_UNDEF (& array -> arPacked [j ]);
3156
+ }
3157
+ return NULL ;
3158
+ }
3159
+ ZVAL_COPY (& array -> arPacked [i ], data );
3160
+ }
3161
+
3162
+ return & iter -> data ;
3163
+ }
3164
+
3165
+ void spl_iterator_zip_move_forward (zend_object_iterator * iter )
3166
+ {
3167
+ spl_zip_iterator * zip_iterator = (spl_zip_iterator * ) iter ;
3168
+
3169
+ for (uint32_t i = 0 ; i < zip_iterator -> iterator_count ; i ++ ) {
3170
+ spl_zip_iterator_entry * current = & zip_iterator -> iterators [i ];
3171
+ if (spl_zip_iterator_is_obj_entry (current )) {
3172
+ current -> obj_iter -> funcs -> move_forward (current -> obj_iter );
3173
+ if (UNEXPECTED (EG (exception ))) {
3174
+ return ;
3175
+ }
3176
+ } else {
3177
+ if (UNEXPECTED (zend_hash_move_forward_ex (current -> array , & current -> hash_position_or_tag ) != SUCCESS )) {
3178
+ return ;
3179
+ }
3180
+ }
3181
+ }
3182
+ }
3183
+
3184
+ void spl_iterator_zip_rewind (zend_object_iterator * iter )
3185
+ {
3186
+ spl_zip_iterator * zip_iterator = (spl_zip_iterator * ) iter ;
3187
+
3188
+ for (uint32_t i = 0 ; i < zip_iterator -> iterator_count ; i ++ ) {
3189
+ spl_zip_iterator_entry * current = & zip_iterator -> iterators [i ];
3190
+ if (spl_zip_iterator_is_obj_entry (current )) {
3191
+ if (current -> obj_iter -> funcs -> rewind ) {
3192
+ current -> obj_iter -> funcs -> rewind (current -> obj_iter );
3193
+ if (UNEXPECTED (EG (exception ))) {
3194
+ return ;
3195
+ }
3196
+ } else if (iter -> index > 0 ) {
3197
+ zend_throw_error (NULL , "Iterator does not support rewinding because one or more sub iterators do not support rewinding" );
3198
+ return ;
3199
+ }
3200
+ } else {
3201
+ zend_hash_internal_pointer_reset_ex (current -> array , & current -> hash_position_or_tag );
3202
+ }
3203
+ }
3204
+ }
3205
+
3206
+ static HashTable * spl_iterator_zip_get_gc (zend_object_iterator * iter , zval * * table , int * n )
3207
+ {
3208
+ spl_zip_iterator * zip_iterator = (spl_zip_iterator * ) iter ;
3209
+
3210
+ HashTable * ht_slot = NULL ;
3211
+
3212
+ // TODO: there can only be one gc_buffer active at a time
3213
+
3214
+ for (uint32_t i = 0 ; i < zip_iterator -> iterator_count ; i ++ ) {
3215
+ // TODO: array ????
3216
+ spl_zip_iterator_entry * current = & zip_iterator -> iterators [i ];
3217
+ if (spl_zip_iterator_is_obj_entry (current )) {
3218
+ if (current -> obj_iter -> funcs -> get_gc ) {
3219
+ //HashTable *ht = current->obj_iter->funcs->get_gc(current->obj_iter, tmp_table, tmp_n);
3220
+ if (ht_slot ) {
3221
+
3222
+ } else {
3223
+ //ht_slot = ht;
3224
+ }
3225
+ }
3226
+ }
3227
+ }
3228
+
3229
+ * table = NULL ;
3230
+ * n = 0 ;
3231
+
3232
+ return ht_slot ;
3233
+ }
3234
+
3235
+ static const zend_object_iterator_funcs spl_iterator_zip_funcs = {
3236
+ spl_iterator_zip_dtor ,
3237
+ spl_iterator_zip_valid ,
3238
+ spl_iterator_zip_get_current_data ,
3239
+ spl_iterator_zip_get_current_key ,
3240
+ spl_iterator_zip_move_forward ,
3241
+ spl_iterator_zip_rewind ,
3242
+ NULL , /* invalidate_current */ // TODO ???
3243
+ spl_iterator_zip_get_gc , /* get_gc */
3244
+ };
3245
+
3246
+ // TODO: by ref support ??? (what happens now when we have a ref-returning generator?)
3247
+ PHP_FUNCTION (iterator_zip )
3248
+ {
3249
+ zval * argv ;
3250
+ uint32_t iterator_count ;
3251
+
3252
+ ZEND_PARSE_PARAMETERS_START (0 , -1 )
3253
+ Z_PARAM_VARIADIC ('*' , argv , iterator_count )
3254
+ ZEND_PARSE_PARAMETERS_END ();
3255
+
3256
+ spl_zip_iterator_entry * iterators = safe_emalloc (iterator_count , sizeof (spl_zip_iterator_entry ), 0 );
3257
+
3258
+ for (uint32_t i = 0 ; i < iterator_count ; i ++ ) {
3259
+ if (UNEXPECTED (!zend_is_iterable (& argv [i ]))) {
3260
+ for (uint32_t j = 0 ; j < i ; j ++ ) {
3261
+ spl_zip_iterator_entry * current = & iterators [i ];
3262
+ if (spl_zip_iterator_is_obj_entry (current )) {
3263
+ zend_iterator_dtor (current -> obj_iter );
3264
+ } else {
3265
+ zval_ptr_dtor (& argv [j ]);
3266
+ }
3267
+ }
3268
+ efree (iterators );
3269
+ zend_argument_value_error (i + 1 , "must be of type iterable, %s given" , zend_zval_value_name (& argv [i ]));
3270
+ RETURN_THROWS ();
3271
+ }
3272
+
3273
+ if (Z_TYPE (argv [i ]) == IS_ARRAY ) {
3274
+ iterators [i ].hash_position_or_tag = 0 ;
3275
+ iterators [i ].array = Z_ARR (argv [i ]);
3276
+ Z_TRY_ADDREF (argv [i ]);
3277
+ } else {
3278
+ ZEND_ASSERT (Z_TYPE (argv [i ]) == IS_OBJECT );
3279
+
3280
+ zend_class_entry * ce = Z_OBJCE_P (& argv [i ]);
3281
+ zend_object_iterator * obj_iter = ce -> get_iterator (ce , & argv [i ], false);
3282
+ iterators [i ].hash_position_or_tag = UINT32_MAX ;
3283
+ iterators [i ].obj_iter = obj_iter ;
3284
+ }
3285
+ }
3286
+
3287
+ spl_zip_iterator * iterator = emalloc (sizeof (* iterator ));
3288
+ zend_iterator_init (& iterator -> intern );
3289
+ ZVAL_UNDEF (& iterator -> intern .data );
3290
+ ZVAL_UNDEF (& iterator -> key_array );
3291
+
3292
+ iterator -> intern .funcs = & spl_iterator_zip_funcs ;
3293
+ iterator -> iterators = iterators ;
3294
+ iterator -> iterator_count = iterator_count ;
3295
+
3296
+ zend_create_internal_iterator_iter (return_value , & iterator -> intern );
3297
+ }
3298
+
3029
3299
static int spl_iterator_count_apply (zend_object_iterator * iter , void * puser ) /* {{{ */
3030
3300
{
3031
3301
if (UNEXPECTED (* (zend_long * )puser == ZEND_LONG_MAX )) {
0 commit comments