diff options
| -rw-r--r-- | Zend/zend_hash.c | 43 | ||||
| -rw-r--r-- | Zend/zend_hash.h | 1 | ||||
| -rw-r--r-- | Zend/zend_operators.c | 99 | ||||
| -rw-r--r-- | Zend/zend_operators.h | 4 | 
4 files changed, 142 insertions, 5 deletions
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 3566c97ce2..af532da0a4 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1068,6 +1068,49 @@ ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,  } +ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar) +{ +	Bucket *p1, *p2; +	int result; + +	IS_CONSISTENT(ht1); +	IS_CONSISTENT(ht2); + +	result = ht1->nNumOfElements - ht2->nNumOfElements; +	if (result!=0) { +		return result; +	} +	p1 = ht1->pListHead; +	p2 = ht2->pListHead; + +	while (p1 && p2) { +		if (p1->nKeyLength==0 && p2->nKeyLength==0) { /* numeric indices */ +			result = p1->h - p2->h; +			if (result!=0) { +				return result; +			} +		} else { /* string indices */ +			result = p1->nKeyLength - p2->nKeyLength; +			if (result!=0) { +				return result; +			} +			result = memcmp(p1->arKey, p2->arKey, p1->nKeyLength); +			if (result!=0) { +				return result; +			} +		} +		result = compar(p1->pData, p2->pData); +		if (result!=0) { +			return result; +		} +		p1 = p1->pListNext; +		p2 = p2->pListNext; +	} + +	return 0; +} + +  ZEND_API int zend_hash_minmax(HashTable *ht, int (*compar) (const void *, const void *), int flag, void **pData)  {  	Bucket *p,*res; diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index abb82123b8..88741ae713 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -166,6 +166,7 @@ ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos  ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size);  ZEND_API void zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite);  ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compare_func, int renumber); +ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar);  ZEND_API int zend_hash_minmax(HashTable *ht, int (*compar)(const void *, const void *), int flag, void **pData);  ZEND_API int zend_hash_num_elements(HashTable *ht); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 57a72358f4..4ffe288887 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1042,6 +1042,7 @@ ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2)  	return SUCCESS;  } +  ZEND_API int compare_function(zval *result, zval *op1, zval *op2)  {  	zval op1_copy, op2_copy; @@ -1075,15 +1076,53 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2)  		result->type = IS_LONG;  		return SUCCESS;  	} -	if ((op1->type==IS_ARRAY || op1->type==IS_OBJECT) -		&& (op2->type==IS_ARRAY || op2->type==IS_OBJECT)) { -		zend_error(E_WARNING,"Cannot compare arrays or objects"); +	if (op1->type==IS_ARRAY && op2->type==IS_ARRAY) { +		zend_compare_arrays(result, op1, op2); +		return SUCCESS; +	} + +	if (op1->type==IS_OBJECT && op2->type==IS_OBJECT) { +		zend_compare_objects(result, op1, op2); +		return SUCCESS; +	} + +	if (op1->type==IS_ARRAY) { +		result->value.lval = 1; +		result->type = IS_LONG; +		return SUCCESS; +	} +	if (op2->type==IS_ARRAY) { +		result->value.lval = -1; +		result->type = IS_LONG; +		return SUCCESS; +	} +	if (op1->type==IS_OBJECT) { +		result->value.lval = 1; +		result->type = IS_LONG; +		return SUCCESS; +	} +	if (op2->type==IS_OBJECT) { +		result->value.lval = -1; +		result->type = IS_LONG; +		return SUCCESS;  	} +  	var_reset(result);  	return FAILURE;  } +static int hash_zval_identical_function(const zval **z1, const zval **z2) +{ +	zval result; + +	if (is_identical_function(&result, (zval *) *z1, (zval *) *z2)==FAILURE) { +		return 0; +	} +	return result.value.lval; +} + +  ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2)  {  	result->type = IS_BOOL; @@ -1116,8 +1155,22 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2)  			return SUCCESS;  			break;  		case IS_ARRAY: +			if (zend_hash_compare(op1->value.ht, op2->value.ht, hash_zval_identical_function)==0) { +				result->value.lval = 1; +			} else { +				result->value.lval = 0; +			} +			break;  		case IS_OBJECT: -			zend_error(E_WARNING,"Cannot compare arrays or objects"); +			if (op1->value.obj.ce != op2->value.obj.ce) { +				result->value.lval = 0; +			} else { +				if (zend_hash_compare(op1->value.obj.properties, op2->value.obj.properties, hash_zval_identical_function)==0) { +					result->value.lval = 1; +				} else { +					result->value.lval = 0; +				} +			}  			break;  	}  	var_reset(result); @@ -1128,7 +1181,7 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2)  ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2)  {     result->type = IS_BOOL; -   if ( is_identical_function( result, op1, op2 ) == FAILURE ) { +   if (is_identical_function( result, op1, op2 ) == FAILURE) {  	  return FAILURE;     }     result->value.lval = !result->value.lval; @@ -1478,6 +1531,42 @@ ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2)  } +static int hash_zval_compare_function(const zval **z1, const zval **z2) +{ +	zval result; + +	if (compare_function(&result, (zval *) *z1, (zval *) *z2)==FAILURE) { +		return 0; +	} +	return result.value.lval; +} + + + +ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2) +{ +	result->type = IS_LONG; +	result->value.lval = zend_hash_compare(ht1, ht2, hash_zval_compare_function); +} + + +ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2) +{ +	zend_compare_symbol_tables(result, a1->value.ht, a2->value.ht); +} + + +ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2) +{ +	if (o1->value.obj.ce != o2->value.obj.ce) { +		result->value.lval = 1;	/* Comparing objects of different types is pretty much meaningless */ +		result->type = IS_LONG; +		return; +	} +	zend_compare_symbol_tables(result, o1->value.obj.properties, o2->value.obj.properties); +} + +  /* returns 0 for non-numeric string   * returns IS_DOUBLE for floating point string, and assigns the value to *dval (if it's not NULL)   * returns IS_LONG for integer strings, and assigns the value to *lval (if it's not NULL) diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index d906660a46..0d1fb6cf92 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -83,6 +83,10 @@ ZEND_API int zend_binary_strncmp(char *s1, uint len1, char *s2, uint len2, uint  ZEND_API int zend_binary_strcasecmp(char *s1, uint len1, char *s2, uint len2);  ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2); +ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2); +ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2); +ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2); +  #define convert_to_ex_master(ppzv, lower_type, upper_type)	\  	if ((*ppzv)->type!=IS_##upper_type) {					\  | 
