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:
Drew Paroski
2013-04-29 23:23:28 -07:00
commit de Sara Golemon
commit 21b8949d23
5 arquivos alterados com 51 adições e 1 exclusões
+5 -1
Ver Arquivo
@@ -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);
+20
Ver Arquivo
@@ -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)