@@ -3026,6 +3026,276 @@ PHP_FUNCTION(iterator_to_array)
30263026 spl_iterator_apply (obj , use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply , (void * )return_value );
30273027} /* }}} */
30283028
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+
30293299static int spl_iterator_count_apply (zend_object_iterator * iter , void * puser ) /* {{{ */
30303300{
30313301 if (UNEXPECTED (* (zend_long * )puser == ZEND_LONG_MAX )) {
0 commit comments