@@ -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