Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge v1.19 into master #1621

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 120 additions & 3 deletions src/BSON/Int64.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,23 @@ static zend_object* php_phongo_int64_clone_object(phongo_compat_object_handler_t
return new_object;
}

static int php_phongo_int64_compare_objects(zval* o1, zval* o2)
static bool php_phongo_int64_is_int64_object(zval* object)
{
php_phongo_int64_t *intern1, *intern2;
if (Z_TYPE_P(object) != IS_OBJECT) {
return false;
}

ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2);
return Z_OBJ_P(object)->ce == php_phongo_int64_ce;
}

static bool php_phongo_int64_is_long_or_double(zval* value)
{
return Z_TYPE_P(value) == IS_LONG || Z_TYPE_P(value) == IS_DOUBLE;
}

static int php_phongo_int64_compare_int64_objects(zval* o1, zval* o2)
{
php_phongo_int64_t *intern1, *intern2;

intern1 = Z_INT64_OBJ_P(o1);
intern2 = Z_INT64_OBJ_P(o2);
Expand All @@ -281,6 +293,105 @@ static int php_phongo_int64_compare_objects(zval* o1, zval* o2)
return 0;
}

static int php_phongo_int64_compare_with_long_or_float(zval* object, zval* value)
{
php_phongo_int64_t* intern;
int64_t long_value;
double double_value;

intern = Z_INT64_OBJ_P(object);

assert(php_phongo_int64_is_long_or_double(value));

switch (Z_TYPE_P(value)) {
case IS_LONG:
long_value = Z_LVAL_P(value);
if (intern->integer != long_value) {
return intern->integer < long_value ? -1 : 1;
}
break;

case IS_DOUBLE:
double_value = Z_DVAL_P(value);
if (intern->integer != double_value) {
return intern->integer < double_value ? -1 : 1;
}
break;

default:
return 0;
}

return 0;
}

static int php_phongo_int64_compare_objects(zval* o1, zval* o2)
{
if (php_phongo_int64_is_int64_object(o1) && php_phongo_int64_is_int64_object(o2)) {
return php_phongo_int64_compare_int64_objects(o1, o2);
}

if (php_phongo_int64_is_int64_object(o1) && php_phongo_int64_is_long_or_double(o2)) {
return php_phongo_int64_compare_with_long_or_float(o1, o2);
}

if (php_phongo_int64_is_long_or_double(o1) && php_phongo_int64_is_int64_object(o2)) {
// Invert the result as we're flipping the values used for comparison
return -1 * php_phongo_int64_compare_with_long_or_float(o2, o1);
}

ZEND_COMPARE_OBJECTS_FALLBACK(o1, o2);

return 0;
}

#if PHP_VERSION_ID < 80000
static int php_phongo_int64_compare_with_other_type(zval* object, zval* value)
{
zval tmp_value;
zval result;
int ret;

if (Z_OBJ_HT_P(object)->cast_object(object, &tmp_value, ((Z_TYPE_P(value) == IS_FALSE || Z_TYPE_P(value) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(value))) == FAILURE) {
zval_ptr_dtor(&tmp_value);
return 1;
}

compare_function(&result, &tmp_value, value);

ret = Z_LVAL(result);
zval_ptr_dtor(&tmp_value);
zval_ptr_dtor(&result);

return ret;
}

static int php_phongo_int64_compare_zvals(zval* result, zval* op1, zval* op2)
{
/* Happy case: compare an int64 object with another object, long, or double */
if ((php_phongo_int64_is_int64_object(op1) || php_phongo_int64_is_long_or_double(op1)) && (php_phongo_int64_is_int64_object(op2) || php_phongo_int64_is_long_or_double(op2))) {
ZVAL_LONG(result, php_phongo_int64_compare_objects(op1, op2));
return SUCCESS;
}

/* When comparing an int64 object with any other type, cast the int64 object to the desired type.
* We know that if op1 is an object, op2 has to be the other type and vice versa. For op2 being
* the object, we can again flip the values used for comparison and multiply the result with -1. */

if (php_phongo_int64_is_int64_object(op1)) {
ZVAL_LONG(result, php_phongo_int64_compare_with_other_type(op1, op2));
return SUCCESS;
}

if (php_phongo_int64_is_int64_object(op2)) {
ZVAL_LONG(result, -1 * php_phongo_int64_compare_with_other_type(op2, op1));
return SUCCESS;
}

return FAILURE;
}
#endif

static zend_result php_phongo_int64_cast_object(phongo_compat_object_handler_type* readobj, zval* retval, int type)
{
php_phongo_int64_t* intern;
Expand Down Expand Up @@ -563,6 +674,12 @@ void php_phongo_int64_init_ce(INIT_FUNC_ARGS)
php_phongo_handler_int64.offset = XtOffsetOf(php_phongo_int64_t, std);
php_phongo_handler_int64.cast_object = php_phongo_int64_cast_object;
php_phongo_handler_int64.do_operation = php_phongo_int64_do_operation;

/* On PHP 7.4, compare_objects is only used when comparing two objects.
* Use the compare handler to compare an object with any other zval */
#if PHP_VERSION_ID < 80000
php_phongo_handler_int64.compare = php_phongo_int64_compare_zvals;
#endif
}

bool phongo_int64_new(zval* object, int64_t integer)
Expand Down
13 changes: 7 additions & 6 deletions tests/bson/bson-int64-compare-004.phpt
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
--TEST--
MongoDB\BSON\Int64 comparisons with scalars (64-bit values, 64-bit platforms only)
--SKIPIF--
<?php if (8 !== PHP_INT_SIZE) { die('skip Only for 64-bit platform'); } ?>
MongoDB\BSON\Int64 comparisons with scalars (64-bit values, all platforms)
--FILE--
<?php

// Use 2**33 to ensure it still fits in a float
$int64 = new MongoDB\BSON\Int64('8589934592');

$tests = [
'matching int' => 8589934592,
'wrong int' => 8589934593,
'matching float' => (float) 2**33,
'wrong int' => 0,
];

foreach ($tests as $name => $value) {
printf('Testing %s: %s' . PHP_EOL, $name, var_export($int64 == $value, true));
}

var_dump($int64 > 123);

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
Testing matching int: true
Testing matching float: true
Testing wrong int: false
bool(true)
===DONE===
26 changes: 26 additions & 0 deletions tests/bson/bson-int64-compare-005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
MongoDB\BSON\Int64 comparisons with scalars (64-bit values, 64-bit platforms only)
--SKIPIF--
<?php if (8 !== PHP_INT_SIZE) { die('skip Only for 64-bit platform'); } ?>
--FILE--
<?php

// Use 2**33 to ensure it still fits in a float
$int64 = new MongoDB\BSON\Int64('8589934592');

$tests = [
'matching int' => 8589934592,
'wrong int' => 8589934593,
];

foreach ($tests as $name => $value) {
printf('Testing %s: %s' . PHP_EOL, $name, var_export($int64 == $value, true));
}

?>
===DONE===
<?php exit(0); ?>
--EXPECT--
Testing matching int: true
Testing wrong int: false
===DONE===