array_slice(): support for collections, remove dead code
A straight-forward delegation to ArrayIter does the job. After analysis of the uses of slicing code, it seems that slicing can be confined to just the ext_array function, since the other uses for func_get_args have been subsumed by special purpose bytecodes. Thus, this diff also removes Array::slice, ArrayUtil::Slice, func_get_arg, and func_get_args. Reviewed By: @jdelong Differential Revision: D1142189
Esse commit está contido em:
@@ -57,38 +57,6 @@ Variant ArrayUtil::Chunk(CArrRef input, int size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
Variant ArrayUtil::Slice(CArrRef input, int offset, int64_t length,
|
||||
bool preserve_keys) {
|
||||
int num_in = input.size();
|
||||
if (offset > num_in) {
|
||||
offset = num_in;
|
||||
} else if (offset < 0 && (offset = (num_in + offset)) < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (length < 0) {
|
||||
length = num_in - offset + length;
|
||||
} else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) {
|
||||
length = num_in - offset;
|
||||
}
|
||||
|
||||
Array out_hash = Array::Create();
|
||||
int pos = 0;
|
||||
ArrayIter iter(input);
|
||||
for (; pos < offset && iter; ++pos, ++iter) {}
|
||||
for (; pos < offset + length && iter; ++pos, ++iter) {
|
||||
Variant key(iter.first());
|
||||
bool doAppend = !preserve_keys && key.isNumeric();
|
||||
CVarRef v = iter.secondRef();
|
||||
if (doAppend) {
|
||||
out_hash.appendWithRef(v);
|
||||
} else {
|
||||
out_hash.setWithRef(key, v, true);
|
||||
}
|
||||
}
|
||||
return out_hash;
|
||||
}
|
||||
|
||||
Variant ArrayUtil::Splice(CArrRef input, int offset, int64_t length /* = 0 */,
|
||||
CVarRef replacement /* = null_variant */,
|
||||
Array *removed /* = NULL */) {
|
||||
|
||||
@@ -36,14 +36,6 @@ public:
|
||||
*/
|
||||
static Variant Chunk(CArrRef input, int size, bool preserve_keys = false);
|
||||
|
||||
/**
|
||||
* Taking a slice. When "preserve_keys" is true, a vector will turn
|
||||
* into numerically keyed map. When "preserve_keys" is false, a map will
|
||||
* turn into vectors, unless keys are not numeric.
|
||||
*/
|
||||
static Variant Slice(CArrRef input, int offset, int64_t length,
|
||||
bool preserve_keys);
|
||||
|
||||
/**
|
||||
* Removes the elements designated by offset and length and replace them
|
||||
* with supplied array.
|
||||
|
||||
@@ -296,11 +296,6 @@ Array &Array::mergeImpl(ArrayData *data) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Array Array::slice(int offset, int length, bool preserve_keys) const {
|
||||
if (m_px == nullptr) return Array();
|
||||
return ArrayUtil::Slice(m_px, offset, length, preserve_keys).toArray();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// comparisons
|
||||
|
||||
|
||||
@@ -200,7 +200,6 @@ public:
|
||||
* into numerically keyed map.
|
||||
*/
|
||||
Array& merge(CArrRef arr);
|
||||
Array slice(int offset, int length, bool preserve_keys) const;
|
||||
|
||||
/*
|
||||
* Sorting.
|
||||
|
||||
@@ -619,7 +619,9 @@ Variant f_array_reverse(CVarRef input, bool preserve_keys /* = false */) {
|
||||
|
||||
const auto& cell_input = *input.asCell();
|
||||
if (UNLIKELY(!isContainer(cell_input))) {
|
||||
throw_expected_array_or_collection_exception();
|
||||
raise_warning("Invalid operand type was used: %s expects "
|
||||
"an array or collection as argument 1",
|
||||
__FUNCTION__+2);
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
@@ -641,13 +643,54 @@ Variant f_array_shift(VRefParam array) {
|
||||
return array.dequeue();
|
||||
}
|
||||
|
||||
Variant f_array_slice(CVarRef array, int offset,
|
||||
Variant f_array_slice(CVarRef input, int offset,
|
||||
CVarRef length /* = null_variant */,
|
||||
bool preserve_keys /* = false */) {
|
||||
getCheckedArray(array);
|
||||
const auto& cell_input = *input.asCell();
|
||||
if (UNLIKELY(!isContainer(cell_input))) {
|
||||
raise_warning("Invalid operand type was used: %s expects "
|
||||
"an array or collection as argument 1",
|
||||
__FUNCTION__+2);
|
||||
return uninit_null();
|
||||
}
|
||||
int64_t len = length.isNull() ? 0x7FFFFFFF : length.toInt64();
|
||||
return ArrayUtil::Slice(arr_array, offset, len, preserve_keys);
|
||||
|
||||
int num_in = getContainerSize(cell_input);
|
||||
if (offset > num_in) {
|
||||
offset = num_in;
|
||||
} else if (offset < 0 && (offset = (num_in + offset)) < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
len = num_in - offset + len;
|
||||
} else if (((unsigned)offset + (unsigned)len) > (unsigned)num_in) {
|
||||
len = num_in - offset;
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
return empty_array;
|
||||
}
|
||||
|
||||
// PackedArrayInit can't be used because non-numeric keys are preserved
|
||||
// even when preserve_keys is false
|
||||
Array ret = Array::attach(HphpArray::MakeReserve(len));
|
||||
int pos = 0;
|
||||
ArrayIter iter(input);
|
||||
for (; pos < offset && iter; ++pos, ++iter) {}
|
||||
for (; pos < (offset + len) && iter; ++pos, ++iter) {
|
||||
Variant key(iter.first());
|
||||
bool doAppend = !preserve_keys && key.isNumeric();
|
||||
CVarRef v = iter.secondRefPlus();
|
||||
if (doAppend) {
|
||||
ret.appendWithRef(v);
|
||||
} else {
|
||||
ret.setWithRef(key, v, true);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Variant f_array_splice(VRefParam input, int offset,
|
||||
CVarRef length /* = null_variant */,
|
||||
CVarRef replacement /* = null_variant */) {
|
||||
|
||||
@@ -313,25 +313,6 @@ Variant f_func_get_arg(int arg_num) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Variant func_get_arg(int num_args, CArrRef params, CArrRef args, int pos) {
|
||||
if (num_args <= params.size()) {
|
||||
if (pos >= 0 && pos < num_args) {
|
||||
return params.rvalAt(pos);
|
||||
}
|
||||
} else {
|
||||
if (pos >= 0) {
|
||||
int index = pos - params.size();
|
||||
if (index < 0) {
|
||||
return params.rvalAt(pos);
|
||||
}
|
||||
if (index < args.size()) {
|
||||
return args.rvalAt(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Array hhvm_get_frame_args(const ActRec* ar, int offset) {
|
||||
if (ar == NULL) {
|
||||
return Array();
|
||||
@@ -375,26 +356,6 @@ Variant f_func_get_args() {
|
||||
FUNC_GET_ARGS_IMPL(0);
|
||||
}
|
||||
|
||||
Array func_get_args(int num_args, CArrRef params, CArrRef args) {
|
||||
if (params.empty() && args.empty()) return Array::Create();
|
||||
if (args.empty()) {
|
||||
if (num_args < params.size()) {
|
||||
return params.slice(0, num_args, false);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
Array derefArgs;
|
||||
for (ArrayIter iter(args); iter; ++iter) {
|
||||
derefArgs.append(iter.second());
|
||||
}
|
||||
|
||||
if (params.empty()) return derefArgs;
|
||||
assert(num_args > params.size());
|
||||
Array ret = Array(params).merge(derefArgs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Variant f_hphp_func_slice_args(int offset) {
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
|
||||
@@ -50,7 +50,6 @@ String f_create_function(const String& args, const String& code);
|
||||
* parameters to help the implementation.
|
||||
*/
|
||||
Variant f_func_get_arg(int arg_num);
|
||||
Variant func_get_arg(int num_args, CArrRef params, CArrRef args, int pos);
|
||||
|
||||
/**
|
||||
* PHP's func_get_args() is transformed to this function with some extra
|
||||
@@ -58,7 +57,6 @@ Variant func_get_arg(int num_args, CArrRef params, CArrRef args, int pos);
|
||||
*/
|
||||
Variant f_func_get_args();
|
||||
Array hhvm_get_frame_args(const ActRec* ar, int offset);
|
||||
Array func_get_args(int num_args, CArrRef params, CArrRef args);
|
||||
|
||||
/**
|
||||
* HipHop extension that allows requesting only a subset of function arguments.
|
||||
|
||||
@@ -452,28 +452,6 @@ bool TestCppBase::TestArray() {
|
||||
VS(arr, make_map_array("n0", "s2", "n1", "s3"));
|
||||
}
|
||||
|
||||
// slice
|
||||
{
|
||||
Array arr = make_packed_array("test1", "test2");
|
||||
Array sub = arr.slice(1, 1, true);
|
||||
VS(sub, make_map_array(1, "test2"));
|
||||
}
|
||||
{
|
||||
Array arr = make_packed_array("test1", "test2");
|
||||
Array sub = arr.slice(1, 1, false);
|
||||
VS(sub, make_packed_array("test2"));
|
||||
}
|
||||
{
|
||||
Array arr = make_map_array("n1", "test1", "n2", "test2");
|
||||
Array sub = arr.slice(1, 1, true);
|
||||
VS(sub, make_map_array("n2", "test2"));
|
||||
}
|
||||
{
|
||||
Array arr = make_map_array("n1", "test1", "n2", "test2");
|
||||
Array sub = arr.slice(1, 1, false);
|
||||
VS(sub, make_map_array("n2", "test2"));
|
||||
}
|
||||
|
||||
// escalation
|
||||
{
|
||||
Array arr;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?hh
|
||||
|
||||
function main() {
|
||||
$input = Vector {"a", "b", "c", "d", "e"};
|
||||
|
||||
var_dump(array_slice($input, 2));
|
||||
var_dump(array_slice($input, 2, null));
|
||||
var_dump(array_slice($input, -2, 1));
|
||||
var_dump(array_slice($input, 0, 3));
|
||||
|
||||
// note the differences in the array keys
|
||||
var_dump(array_slice($input, 2, -1));
|
||||
var_dump(array_slice($input, 2, -1, true));
|
||||
|
||||
var_dump(array_slice(Vector {"a", "b", "c"}, 1, 2, true));
|
||||
var_dump(array_slice(Vector {"a", "b", "c"}, 1, 2, false));
|
||||
|
||||
$m = Map {"a" => "g", 0 => "a", 1 => "b", 2 => "c"};
|
||||
unset($m['a']);
|
||||
var_dump(array_slice($m, 1, 2, true));
|
||||
var_dump(array_slice($m, 1, 2, false));
|
||||
|
||||
$m = Map {"a" => 123, 0 => "a", 1 => "b", 2 => "c"};
|
||||
unset($m['a']);
|
||||
var_dump(array_slice($m, 1, 2, true));
|
||||
var_dump(array_slice($m, 1, 2, false));
|
||||
|
||||
var_dump(array_slice(FrozenVector{123, "b", "c"}, 1, 2, true));
|
||||
var_dump(array_slice(FrozenVector{123, "b", "c"}, 1, 2, false));
|
||||
|
||||
var_dump(array_slice(Set {"a", "b", "c"}, 1, 2, true));
|
||||
var_dump(array_slice(FrozenSet {"a", "b", "c"}, 1, 2, false));
|
||||
}
|
||||
main();
|
||||
@@ -0,0 +1,100 @@
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(1) "c"
|
||||
[1]=>
|
||||
string(1) "d"
|
||||
[2]=>
|
||||
string(1) "e"
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(1) "c"
|
||||
[1]=>
|
||||
string(1) "d"
|
||||
[2]=>
|
||||
string(1) "e"
|
||||
}
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(1) "d"
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(1) "a"
|
||||
[1]=>
|
||||
string(1) "b"
|
||||
[2]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(1) "c"
|
||||
[1]=>
|
||||
string(1) "d"
|
||||
}
|
||||
array(2) {
|
||||
[2]=>
|
||||
string(1) "c"
|
||||
[3]=>
|
||||
string(1) "d"
|
||||
}
|
||||
array(2) {
|
||||
[1]=>
|
||||
string(1) "b"
|
||||
[2]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(1) "b"
|
||||
[1]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
[1]=>
|
||||
string(1) "b"
|
||||
[2]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(1) "b"
|
||||
[1]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
[1]=>
|
||||
string(1) "b"
|
||||
[2]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(1) "b"
|
||||
[1]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
[1]=>
|
||||
string(1) "b"
|
||||
[2]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(1) "b"
|
||||
[1]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
["b"]=>
|
||||
string(1) "b"
|
||||
["c"]=>
|
||||
string(1) "c"
|
||||
}
|
||||
array(2) {
|
||||
["b"]=>
|
||||
string(1) "b"
|
||||
["c"]=>
|
||||
string(1) "c"
|
||||
}
|
||||
Referência em uma Nova Issue
Bloquear um usuário