Make array_key_exists support collections efficiently
array_key_exists() was converting collections to arrays before checking if a key exists, which is an O(n) operation (which also has the annoying side effect of changing int-like string keys to int keys.) This diff makes array_key_exists natively support collections (which also addresses the pesky int-like string key -> int key issue).
Esse commit está contido em:
@@ -194,10 +194,14 @@ bool f_array_key_exists(CVarRef key, CVarRef search) {
|
||||
if (LIKELY(saccType == KindOfArray)) {
|
||||
ad = Variant::GetArrayData(sacc);
|
||||
} else if (saccType == KindOfObject) {
|
||||
ObjectData* obj = Variant::GetObjectData(sacc);
|
||||
if (obj->isCollection()) {
|
||||
return collectionOffsetContains(obj, key);
|
||||
}
|
||||
return f_array_key_exists(key, toArray(search));
|
||||
} else {
|
||||
throw_bad_type_exception("array_key_exists expects an array or an object; "
|
||||
"false returned.");
|
||||
"false returned.");
|
||||
return false;
|
||||
}
|
||||
Variant::TypedValueAccessor kacc = key.getTypedAccessor();
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "runtime/base/types.h"
|
||||
#include "runtime/ext/ext_closure.h"
|
||||
#include "runtime/ext/ext_continuation.h"
|
||||
#include "runtime/ext/ext_collections.h"
|
||||
#include "runtime/vm/bytecode.h"
|
||||
#include "runtime/vm/runtime.h"
|
||||
#include "runtime/base/stats.h"
|
||||
@@ -4547,6 +4548,9 @@ static int64_t ak_exist_int(int64_t key, ArrayData* arr) {
|
||||
|
||||
HOT_FUNC_VM
|
||||
static int64_t ak_exist_string_obj(StringData* key, ObjectData* obj) {
|
||||
if (obj->isCollection()) {
|
||||
return collectionOffsetContains(obj, key);
|
||||
}
|
||||
CArrRef arr = obj->o_toArray();
|
||||
int64_t res = ak_exist_string_helper(key, arr.get());
|
||||
return res;
|
||||
@@ -4554,6 +4558,9 @@ static int64_t ak_exist_string_obj(StringData* key, ObjectData* obj) {
|
||||
|
||||
HOT_FUNC_VM
|
||||
static int64_t ak_exist_int_obj(int64_t key, ObjectData* obj) {
|
||||
if (obj->isCollection()) {
|
||||
return collectionOffsetContains(obj, key);
|
||||
}
|
||||
CArrRef arr = obj->o_toArray();
|
||||
bool res = arr.get()->exists(key);
|
||||
return res;
|
||||
|
||||
@@ -8215,6 +8215,9 @@ static int64_t ak_exist_int(int64_t key, ArrayData* arr) {
|
||||
}
|
||||
|
||||
static int64_t ak_exist_string_obj(StringData* key, ObjectData* obj) {
|
||||
if (obj->isCollection()) {
|
||||
return collectionOffsetContains(obj, key);
|
||||
}
|
||||
CArrRef arr = obj->o_toArray();
|
||||
int64_t res = ak_exist_string_helper(key, arr.get());
|
||||
decRefObj(obj);
|
||||
@@ -8223,6 +8226,9 @@ static int64_t ak_exist_string_obj(StringData* key, ObjectData* obj) {
|
||||
}
|
||||
|
||||
static int64_t ak_exist_int_obj(int64_t key, ObjectData* obj) {
|
||||
if (obj->isCollection()) {
|
||||
return collectionOffsetContains(obj, key);
|
||||
}
|
||||
CArrRef arr = obj->o_toArray();
|
||||
bool res = arr.get()->exists(key);
|
||||
decRefObj(obj);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
function f() {
|
||||
$m = Map {1 => 'a', '2' => 'b'};
|
||||
var_dump(array_key_exists(1, $m));
|
||||
var_dump(array_key_exists('1', $m));
|
||||
var_dump(array_key_exists(2, $m));
|
||||
var_dump(array_key_exists('2', $m));
|
||||
var_dump(array_key_exists(3, $m));
|
||||
var_dump(array_key_exists('3', $m));
|
||||
echo "========\n";
|
||||
$x = 'array_key_exists';
|
||||
$x[0] = 'a';
|
||||
var_dump($x(1, $m));
|
||||
var_dump($x('1', $m));
|
||||
var_dump($x(2, $m));
|
||||
var_dump($x('2', $m));
|
||||
var_dump($x(3, $m));
|
||||
var_dump($x('3', $m));
|
||||
}
|
||||
f();
|
||||
@@ -0,0 +1,13 @@
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
========
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(false)
|
||||
Referência em uma Nova Issue
Bloquear um usuário