From: Zeev Suraski Date: Sun, 4 Jun 2000 21:59:49 +0000 (+0000) Subject: - Support unordered hash comparisons X-Git-Tag: PRE_EIGHT_BYTE_ALLOC_PATCH~112 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bfac4633a512f9a91fb3ba3700f2124e5139a4ba;p=php - Support unordered hash comparisons - Make == perform an unordered comparison with arrays/objects, and === perform an ordered comparison --- diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index af532da0a4..6eebc8de28 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1068,10 +1068,11 @@ 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) +ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered) { Bucket *p1, *p2; int result; + void *pData2; IS_CONSISTENT(ht1); IS_CONSISTENT(ht2); @@ -1080,31 +1081,52 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co if (result!=0) { return result; } + p1 = ht1->pListHead; - p2 = ht2->pListHead; + if (ordered) { + 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; + while (p1) { + if (ordered && !p2) { + return 1; /* That's not supposed to happen */ + } + if (ordered) { + 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 = memcmp(p1->arKey, p2->arKey, p1->nKeyLength); - if (result!=0) { - return result; + pData2 = p2->pData; + } else { + if (p1->nKeyLength==0) { /* numeric index */ + if (zend_hash_index_find(ht2, p1->h, &pData2)==FAILURE) { + return 1; + } + } else { /* string index */ + if (zend_hash_find(ht2, p1->arKey, p1->nKeyLength, &pData2)==FAILURE) { + return 1; + } } } - result = compar(p1->pData, p2->pData); + result = compar(p1->pData, pData2); if (result!=0) { return result; } p1 = p1->pListNext; - p2 = p2->pListNext; + if (ordered) { + p2 = p2->pListNext; + } } return 0; diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 88741ae713..13f03c4357 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -166,7 +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_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered); 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 4ffe288887..e9f9e91e8f 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1116,10 +1116,15 @@ static int hash_zval_identical_function(const zval **z1, const zval **z2) { zval result; + /* is_identical_function() returns 1 in case of identity and 0 in case + * of a difference; + * whereas this comparison function is expected to return 0 on identity, + * and non zero otherwise. + */ if (is_identical_function(&result, (zval *) *z1, (zval *) *z2)==FAILURE) { - return 0; + return 1; } - return result.value.lval; + return !result.value.lval; } @@ -1133,17 +1138,14 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2) switch (op1->type) { case IS_NULL: result->value.lval = (op2->type==IS_NULL); - return SUCCESS; break; case IS_BOOL: case IS_LONG: case IS_RESOURCE: result->value.lval = (op1->value.lval == op2->value.lval); - return SUCCESS; break; case IS_DOUBLE: result->value.lval = (op1->value.dval == op2->value.dval); - return SUCCESS; break; case IS_STRING: if ((op1->value.str.len == op2->value.str.len) @@ -1152,10 +1154,9 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2) } else { result->value.lval = 0; } - return SUCCESS; break; case IS_ARRAY: - if (zend_hash_compare(op1->value.ht, op2->value.ht, hash_zval_identical_function)==0) { + if (zend_hash_compare(op1->value.ht, op2->value.ht, hash_zval_identical_function, 1)==0) { result->value.lval = 1; } else { result->value.lval = 0; @@ -1165,16 +1166,18 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2) 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) { + if (zend_hash_compare(op1->value.obj.properties, op2->value.obj.properties, hash_zval_identical_function, 1)==0) { result->value.lval = 1; } else { result->value.lval = 0; } } break; + default: + var_reset(result); + return FAILURE; } - var_reset(result); - return FAILURE; + return SUCCESS; } @@ -1536,7 +1539,7 @@ 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 1; } return result.value.lval; } @@ -1546,7 +1549,7 @@ static int hash_zval_compare_function(const zval **z1, const zval **z2) 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); + result->value.lval = zend_hash_compare(ht1, ht2, hash_zval_compare_function, 0); }