cii-text-analysis/vendor/rubix/tensor/ext/kernel/array.c
Jéremy Munsch f68d2ac333
premier poc
2026-02-11 08:24:04 +01:00

1059 lines
27 KiB
C

/*
* This file is part of the Zephir.
*
* (c) Phalcon Team <team@zephir-lang.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code. If you did not receive
* a copy of the license it is available through the world-wide-web at the
* following url: https://docs.zephir-lang.com/en/latest/license
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <php.h>
#include "php_ext.h"
#include <ext/standard/php_array.h>
#include <Zend/zend_hash.h>
#include <Zend/zend_interfaces.h>
#include "kernel/main.h"
#include "kernel/memory.h"
#include "kernel/debug.h"
#include "kernel/array.h"
#include "kernel/operators.h"
#include "kernel/backtrace.h"
#include "kernel/object.h"
#include "kernel/fcall.h"
void ZEPHIR_FASTCALL zephir_create_array(zval *return_value, uint32_t size, int initialize)
{
uint32_t i;
zval null_value;
HashTable *hashTable;
ZVAL_NULL(&null_value);
array_init_size(return_value, size);
hashTable = Z_ARRVAL_P(return_value);
if (size > 0) {
zend_hash_real_init(hashTable, 0);
if (initialize) {
for (i = 0; i < size; i++) {
zend_hash_next_index_insert(hashTable, &null_value);
}
}
}
}
/**
* Simple convenience function which ensures that you are dealing with an array and you can
* eliminate noise from your code.
*
* It's a bit strange but the refcount for an empty array is always zero somehow.
* There is another strange phenomenon: these zvals does not have any type_flag value.
* Thus we should recreate a new empty array so that it has correct refcount
* value and type_flag. This magic behavior was introduced since PHP 7.3.
*
* Steps to reproduce:
*
* Userland:
* $object->method([10 => []]);
*
* Zephir:
* public function method(array p)
* {
* let p[10]["str"] = "foo";
* }
*/
void
ZEPHIR_FASTCALL zephir_ensure_array(zval *zv)
{
if (
Z_TYPE_P(zv) == IS_ARRAY &&
zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0 &&
(!Z_REFCOUNTED_P(zv) || Z_REFCOUNT_P(zv) < 1)
) {
zephir_create_array(zv, 0, 0);
}
}
int zephir_array_isset_fetch(zval *fetched, const zval *arr, zval *index, int readonly)
{
HashTable *h;
zval *result;
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval exist;
ZVAL_UNDEF(&exist);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, index);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(fetched, (zval *)arr, "offsetget", NULL, 0, index);
if (readonly) {
Z_TRY_DELREF_P(fetched);
}
return 1;
}
ZVAL_NULL(fetched);
return 0;
} else if (UNEXPECTED(Z_TYPE_P(arr) != IS_ARRAY)) {
ZVAL_NULL(fetched);
return 0;
}
h = Z_ARRVAL_P(arr);
switch (Z_TYPE_P(index)) {
case IS_NULL:
result = zend_hash_str_find(h, SL(""));
break;
case IS_DOUBLE:
result = zend_hash_index_find(h, (zend_ulong)Z_DVAL_P(index));
break;
case IS_LONG:
case IS_RESOURCE:
result = zend_hash_index_find(h, Z_LVAL_P(index));
break;
case IS_TRUE:
case IS_FALSE:
result = zend_hash_index_find(h, Z_TYPE_P(index) == IS_TRUE ? 1 : 0);
break;
case IS_STRING:
result = zend_symtable_str_find(h, (Z_STRLEN_P(index) ? Z_STRVAL_P(index) : ""), Z_STRLEN_P(index));
break;
default:
zend_error(E_WARNING, "Illegal offset type %d", Z_TYPE_P(index));
return 0;
}
if (result != NULL) {
zephir_ensure_array(result);
if (!readonly) {
ZVAL_COPY(fetched, result);
} else {
ZVAL_COPY_VALUE(fetched, result);
}
return 1;
}
ZVAL_NULL(fetched);
return 0;
}
int zephir_array_isset_string_fetch(zval *fetched, const zval *arr, char *index, uint32_t index_length, int readonly)
{
zval *zv;
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval exist, offset;
ZVAL_UNDEF(&exist);
ZVAL_STRINGL(&offset, index, index_length);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, &offset);
zval_ptr_dtor(&offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(fetched, (zval *)arr, "offsetget", NULL, 0, &offset);
if (readonly) {
Z_TRY_DELREF_P(fetched);
}
return 1;
}
ZVAL_NULL(fetched);
return 0;
} else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
if ((zv = zend_hash_str_find(Z_ARRVAL_P(arr), index, index_length)) != NULL) {
zephir_ensure_array(zv);
if (!readonly) {
ZVAL_COPY(fetched, zv);
} else {
ZVAL_COPY_VALUE(fetched, zv);
}
return 1;
}
}
ZVAL_NULL(fetched);
return 0;
}
int zephir_array_isset_long_fetch(zval *fetched, const zval *arr, unsigned long index, int readonly)
{
zval *zv;
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval exist, offset;
ZVAL_UNDEF(&exist);
ZVAL_LONG(&offset, index);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, &offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(fetched, (zval *)arr, "offsetget", NULL, 0, &offset);
if (readonly) {
Z_TRY_DELREF_P(fetched);
}
return 1;
}
ZVAL_NULL(fetched);
return 0;
} else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
if ((zv = zend_hash_index_find(Z_ARRVAL_P(arr), index)) != NULL) {
zephir_ensure_array(zv);
if (!readonly) {
ZVAL_COPY(fetched, zv);
} else {
ZVAL_COPY_VALUE(fetched, zv);
}
return 1;
}
}
ZVAL_NULL(fetched);
return 0;
}
int ZEPHIR_FASTCALL zephir_array_isset(const zval *arr, zval *index)
{
HashTable *h;
if (UNEXPECTED(!arr)) {
return 0;
}
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval exist;
ZVAL_UNDEF(&exist);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, index);
if (zend_is_true(&exist)) {
return 1;
}
return 0;
} else if (UNEXPECTED(Z_TYPE_P(arr) != IS_ARRAY)) {
return 0;
}
h = Z_ARRVAL_P(arr);
switch (Z_TYPE_P(index)) {
case IS_NULL:
return zend_hash_str_exists(h, SL(""));
case IS_DOUBLE:
return zend_hash_index_exists(h, (zend_ulong)Z_DVAL_P(index));
case IS_TRUE:
case IS_FALSE:
return zend_hash_index_exists(h, Z_TYPE_P(index) == IS_TRUE ? 1 : 0);
case IS_LONG:
case IS_RESOURCE:
return zend_hash_index_exists(h, Z_LVAL_P(index));
case IS_STRING:
return zend_symtable_str_exists(h, Z_STRVAL_P(index), Z_STRLEN_P(index));
default:
zend_error(E_WARNING, "Illegal offset type");
return 0;
}
}
int ZEPHIR_FASTCALL zephir_array_isset_string(const zval *arr, const char *index, uint32_t index_length)
{
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval exist, offset;
ZVAL_UNDEF(&exist);
ZVAL_STRINGL(&offset, index, index_length);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, &offset);
zval_ptr_dtor(&offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
return 1;
}
return 0;
} else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
return zend_hash_str_exists(Z_ARRVAL_P(arr), index, index_length);
}
return 0;
}
int ZEPHIR_FASTCALL zephir_array_isset_long(const zval *arr, unsigned long index)
{
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev((zval *)arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval exist, offset;
ZVAL_UNDEF(&exist);
ZVAL_LONG(&offset, index);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(&exist, (zval *)arr, "offsetexists", NULL, 0, &offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE && zend_is_true(&exist)) {
return 1;
}
return 0;
} else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
return zend_hash_index_exists(Z_ARRVAL_P(arr), index);
}
return 0;
}
int ZEPHIR_FASTCALL zephir_array_unset(zval *arr, zval *index, int flags)
{
HashTable *ht;
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetunset", NULL, 0, index);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
return 1;
}
return 0;
} else if (Z_TYPE_P(arr) != IS_ARRAY) {
return 0;
}
if ((flags & PH_SEPARATE) == PH_SEPARATE) {
SEPARATE_ZVAL_IF_NOT_REF(arr);
}
ht = Z_ARRVAL_P(arr);
switch (Z_TYPE_P(index)) {
case IS_NULL:
return (zend_hash_str_del(ht, "", 1) == SUCCESS);
case IS_DOUBLE:
return (zend_hash_index_del(ht, (zend_ulong)Z_DVAL_P(index)) == SUCCESS);
case IS_TRUE:
return (zend_hash_index_del(ht, 1) == SUCCESS);
case IS_FALSE:
return (zend_hash_index_del(ht, 0) == SUCCESS);
case IS_LONG:
case IS_RESOURCE:
return (zend_hash_index_del(ht, Z_LVAL_P(index)) == SUCCESS);
case IS_STRING:
return (zend_symtable_del(ht, Z_STR_P(index)) == SUCCESS);
default:
zend_error(E_WARNING, "Illegal offset type");
return 0;
}
}
int ZEPHIR_FASTCALL zephir_array_unset_string(zval *arr, const char *index, uint32_t index_length, int flags)
{
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval offset;
ZVAL_STRINGL(&offset, index, index_length);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetunset", NULL, 0, &offset);
zval_ptr_dtor(&offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
return 1;
}
return 0;
} else if (Z_TYPE_P(arr) != IS_ARRAY) {
return 0;
}
if ((flags & PH_SEPARATE) == PH_SEPARATE) {
SEPARATE_ZVAL_IF_NOT_REF(arr);
}
return zend_hash_str_del(Z_ARRVAL_P(arr), index, index_length);
}
int ZEPHIR_FASTCALL zephir_array_unset_long(zval *arr, unsigned long index, int flags)
{
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval offset;
ZVAL_LONG(&offset, index);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetunset", NULL, 0, &offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
return 1;
}
return 0;
} else if (Z_TYPE_P(arr) != IS_ARRAY) {
return 0;
}
if ((flags & PH_SEPARATE) == PH_SEPARATE) {
SEPARATE_ZVAL_IF_NOT_REF(arr);
}
return zend_hash_index_del(Z_ARRVAL_P(arr), index);
}
int zephir_array_append(zval *arr, zval *value, int flags ZEPHIR_DEBUG_PARAMS)
{
if (Z_TYPE_P(arr) != IS_ARRAY) {
zend_error(E_WARNING, "Cannot use a scalar value as an array in %s on line %d", file, line);
return FAILURE;
}
if ((flags & PH_SEPARATE) == PH_SEPARATE) {
SEPARATE_ZVAL_IF_NOT_REF(arr);
}
Z_TRY_ADDREF_P(value);
return add_next_index_zval(arr, value);
}
int zephir_array_fetch(zval *return_value, zval *arr, zval *index, int flags ZEPHIR_DEBUG_PARAMS)
{
zval *zv;
HashTable *ht;
int result = SUCCESS, found = 0;
zend_ulong uidx = 0;
char *sidx = NULL;
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(return_value, arr, "offsetget", NULL, 0, index);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
if ((flags & PH_READONLY) == PH_READONLY) {
Z_TRY_DELREF_P(return_value);
}
return SUCCESS;
}
return FAILURE;
} else if (Z_TYPE_P(arr) == IS_ARRAY) {
ht = Z_ARRVAL_P(arr);
switch (Z_TYPE_P(index)) {
case IS_NULL:
found = (zv = zend_hash_str_find(ht, SL(""))) != NULL;
sidx = "";
break;
case IS_DOUBLE:
uidx = (zend_ulong)Z_DVAL_P(index);
found = (zv = zend_hash_index_find(ht, uidx)) != NULL;
break;
case IS_LONG:
case IS_RESOURCE:
uidx = Z_LVAL_P(index);
found = (zv = zend_hash_index_find(ht, uidx)) != NULL;
break;
case IS_FALSE:
uidx = 0;
found = (zv = zend_hash_index_find(ht, uidx)) != NULL;
break;
case IS_TRUE:
uidx = 1;
found = (zv = zend_hash_index_find(ht, uidx)) != NULL;
break;
case IS_STRING:
sidx = Z_STRLEN_P(index) ? Z_STRVAL_P(index) : "";
found = (zv = zend_symtable_str_find(ht, Z_STRVAL_P(index), Z_STRLEN_P(index))) != NULL;
break;
default:
if ((flags & PH_NOISY) == PH_NOISY) {
zend_error(E_WARNING, "Illegal offset type in %s on line %d", file, line);
}
result = FAILURE;
break;
}
if (result != FAILURE && found == 1) {
if ((flags & PH_READONLY) == PH_READONLY) {
ZVAL_COPY_VALUE(return_value, zv);
} else {
ZVAL_COPY(return_value, zv);
}
return SUCCESS;
}
if ((flags & PH_NOISY) == PH_NOISY) {
if (sidx == NULL) {
zend_error(E_NOTICE, "Undefined index: %ld in %s on line %d", uidx, file, line);
} else {
zend_error(E_NOTICE, "Undefined index: %s in %s on line %d", sidx, file, line);
}
}
}
ZVAL_NULL(return_value);
return FAILURE;
}
int zephir_array_fetch_string(zval *return_value, zval *arr, const char *index, uint32_t index_length, int flags ZEPHIR_DEBUG_PARAMS)
{
zval *zv;
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval offset;
ZVAL_STRINGL(&offset, index, index_length);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(return_value, arr, "offsetget", NULL, 0, &offset);
zval_ptr_dtor(&offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
if ((flags & PH_READONLY) == PH_READONLY) {
Z_TRY_DELREF_P(return_value);
}
return SUCCESS;
}
return FAILURE;
} else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
if ((zv = zend_hash_str_find(Z_ARRVAL_P(arr), index, index_length)) != NULL) {
if ((flags & PH_READONLY) == PH_READONLY) {
ZVAL_COPY_VALUE(return_value, zv);
} else {
ZVAL_COPY(return_value, zv);
}
return SUCCESS;
}
if ((flags & PH_NOISY) == PH_NOISY) {
zend_error(E_NOTICE, "Undefined index: %s", index);
}
} else {
if ((flags & PH_NOISY) == PH_NOISY) {
zend_error(E_NOTICE, "Cannot use a scalar value as an array in %s on line %d", file, line);
}
}
if (return_value == NULL) {
zend_error(E_ERROR, "No return value passed to zephir_array_fetch_string");
return FAILURE;
}
ZVAL_NULL(return_value);
return FAILURE;
}
int zephir_array_fetch_long(zval *return_value, zval *arr, unsigned long index, int flags ZEPHIR_DEBUG_PARAMS)
{
zval *zv;
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval offset;
ZVAL_LONG(&offset, index);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(return_value, arr, "offsetget", NULL, 0, &offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
if ((flags & PH_READONLY) == PH_READONLY) {
Z_TRY_DELREF_P(return_value);
}
return SUCCESS;
}
return FAILURE;
} else if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) {
if ((zv = zend_hash_index_find(Z_ARRVAL_P(arr), index)) != NULL) {
if ((flags & PH_READONLY) == PH_READONLY) {
ZVAL_COPY_VALUE(return_value, zv);
} else {
ZVAL_COPY(return_value, zv);
}
return SUCCESS;
}
if ((flags & PH_NOISY) == PH_NOISY) {
zend_error(E_NOTICE, "Undefined index: %lu", index);
}
} else {
if ((flags & PH_NOISY) == PH_NOISY) {
zend_error(E_NOTICE, "Cannot use a scalar value as an array in %s on line %d", file, line);
}
}
if (return_value == NULL) {
zend_error(E_ERROR, "No return value passed to zephir_array_fetch_string");
return FAILURE;
}
ZVAL_NULL(return_value);
return FAILURE;
}
/**
* Appends every element of an array at the end of the left array
*/
void zephir_merge_append(zval *left, zval *values)
{
if (Z_TYPE_P(left) != IS_ARRAY) {
zend_error(E_NOTICE, "First parameter of zephir_merge_append must be an array");
return;
}
if (Z_TYPE_P(values) == IS_ARRAY) {
zval *tmp;
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(values), tmp) {
Z_TRY_ADDREF_P(tmp);
add_next_index_zval(left, tmp);
} ZEND_HASH_FOREACH_END();
} else {
Z_TRY_ADDREF_P(values);
add_next_index_zval(left, values);
}
}
int zephir_array_update_zval(zval *arr, zval *index, zval *value, int flags)
{
HashTable *ht;
zval *ret = NULL;
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetset", NULL, 0, index, value);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
return SUCCESS;
}
return FAILURE;
} else if (Z_TYPE_P(arr) != IS_ARRAY) {
zend_error(E_WARNING, "Cannot use a scalar value as an array (2)");
return FAILURE;
}
if ((flags & PH_CTOR) == PH_CTOR) {
zval new_zv;
//Z_TRY_DELREF_P(value); //?
ZVAL_DUP(&new_zv, value);
value = &new_zv;
}
if ((flags & PH_SEPARATE) == PH_SEPARATE) {
SEPARATE_ZVAL_IF_NOT_REF(arr);
}
if ((flags & PH_COPY) == PH_COPY) {
Z_TRY_ADDREF_P(value);
}
ht = Z_ARRVAL_P(arr);
switch (Z_TYPE_P(index)) {
case IS_NULL:
ret = zend_symtable_str_update(ht, "", 1, value);
break;
case IS_DOUBLE:
ret = zend_hash_index_update(ht, (zend_ulong)Z_DVAL_P(index), value);
break;
case IS_LONG:
case IS_RESOURCE:
ret = zend_hash_index_update(ht, Z_LVAL_P(index), value);
break;
case IS_TRUE:
case IS_FALSE:
ret = zend_hash_index_update(ht, Z_TYPE_P(index) == IS_TRUE ? 1 : 0, value);
break;
case IS_STRING:
ret = zend_symtable_str_update(ht, Z_STRVAL_P(index), Z_STRLEN_P(index), value);
break;
default:
zend_error(E_WARNING, "Illegal offset type");
return FAILURE;
}
return ret != NULL ? FAILURE : SUCCESS;
}
int zephir_array_update_string(zval *arr, const char *index, uint32_t index_length, zval *value, int flags)
{
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval offset;
ZVAL_STRINGL(&offset, index, index_length);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetset", NULL, 0, &offset, value);
zval_ptr_dtor(&offset);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
return SUCCESS;
}
return FAILURE;
} else if (Z_TYPE_P(arr) != IS_ARRAY) {
zend_error(E_WARNING, "Cannot use a scalar value as an array (3)");
return FAILURE;
}
if ((flags & PH_CTOR) == PH_CTOR) {
zval new_value;
ZVAL_DUP(&new_value, value);
value = &new_value;
} else if ((flags & PH_COPY) == PH_COPY) {
Z_TRY_ADDREF_P(value);
}
if ((flags & PH_SEPARATE) == PH_SEPARATE) {
SEPARATE_ZVAL_IF_NOT_REF(arr);
}
return zend_hash_str_update(Z_ARRVAL_P(arr), index, index_length, value) ? SUCCESS : FAILURE;
}
int zephir_array_update_long(zval *arr, unsigned long index, zval *value, int flags ZEPHIR_DEBUG_PARAMS)
{
if (UNEXPECTED(Z_TYPE_P(arr) == IS_OBJECT && zephir_instance_of_ev(arr, (const zend_class_entry *)zend_ce_arrayaccess))) {
zend_long ZEPHIR_LAST_CALL_STATUS;
zval offset;
ZVAL_LONG(&offset, index);
ZEPHIR_CALL_METHOD_WITHOUT_OBSERVE(NULL, arr, "offsetset", NULL, 0, &offset, value);
if (ZEPHIR_LAST_CALL_STATUS != FAILURE) {
return SUCCESS;
}
return FAILURE;
} else if (Z_TYPE_P(arr) != IS_ARRAY) {
zend_error(E_WARNING, "Cannot use a scalar value as an array in %s on line %d", file, line);
return FAILURE;
}
if ((flags & PH_CTOR) == PH_CTOR) {
zval new_value;
ZVAL_DUP(&new_value, value);
value = &new_value;
} else if ((flags & PH_COPY) == PH_COPY) {
Z_TRY_ADDREF_P(value);
}
if ((flags & PH_SEPARATE) == PH_SEPARATE) {
SEPARATE_ZVAL_IF_NOT_REF(arr);
}
return zend_hash_index_update(Z_ARRVAL_P(arr), index, value) ? SUCCESS : FAILURE;
}
void zephir_array_keys(zval *return_value, zval *input)
{
zval *entry, new_val;
zend_ulong num_idx;
zend_string *str_idx;
if (EXPECTED(Z_TYPE_P(input) == IS_ARRAY)) {
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));
zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
/* Go through input array and add keys to the return array */
ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
if (str_idx) {
ZVAL_STR_COPY(&new_val, str_idx);
} else {
ZVAL_LONG(&new_val, num_idx);
}
ZEND_HASH_FILL_ADD(&new_val);
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FILL_END();
}
entry = NULL;
str_idx = NULL;
num_idx = 0;
ZVAL_UNDEF(&new_val);
}
int zephir_array_key_exists(zval *arr, zval *key)
{
HashTable *h = Z_ARRVAL_P(arr);
if (h) {
switch (Z_TYPE_P(key)) {
case IS_STRING:
return zend_symtable_exists(h, Z_STR_P(key));
case IS_LONG:
return zend_hash_index_exists(h, Z_LVAL_P(key));
case IS_NULL:
return zend_hash_str_exists(h, "", 1);
default:
zend_error(E_WARNING, "The key should be either a string or an integer");
return 0;
}
}
return 0;
}
/**
* Implementation of Multiple array-offset update
*/
void zephir_array_update_multi_ex(zval *arr, zval *value, const char *types, int types_length, int types_count, va_list ap)
{
char *s;
zval *item;
zval pzv;
zend_array *p;
int i, j, l, ll, re_update, must_continue, wrap_tmp;
ZVAL_UNDEF(&pzv);
if (Z_TYPE_P(arr) != IS_ARRAY) {
zend_error(E_ERROR, "Cannot use a scalar value as an array (multi)");
return;
}
p = Z_ARRVAL_P(arr);
for (i = 0; i < types_length; ++i) {
zval tmp;
zval fetched;
ZVAL_UNDEF(&fetched);
re_update = 0;
must_continue = 0;
wrap_tmp = 0;
ZVAL_ARR(&pzv, p);
switch (types[i]) {
case 's':
s = va_arg(ap, char*);
l = va_arg(ap, int);
if (zephir_array_isset_string_fetch(&fetched, &pzv, s, l, 1)) {
if (Z_TYPE(fetched) == IS_ARRAY) {
if (i == (types_length - 1)) {
re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
zephir_array_update_string(&pzv, s, l, value, PH_COPY | PH_SEPARATE);
p = Z_ARRVAL(pzv);
} else {
re_update = !Z_REFCOUNTED(fetched) || (Z_REFCOUNT(fetched) > 1 && !Z_ISREF(fetched));
if (re_update) {
ZVAL_DUP(&tmp, &fetched);
zephir_array_update_string(&pzv, s, l, &tmp, 0);
p = Z_ARRVAL(tmp);
} else {
p = Z_ARRVAL(fetched);
}
}
must_continue = 1;
}
}
if (!must_continue) {
ZVAL_ARR(&pzv, p);
re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
if (i == (types_length - 1)) {
zephir_array_update_string(&pzv, s, l, value, PH_COPY | PH_SEPARATE);
p = Z_ARRVAL(pzv);
} else {
array_init(&tmp);
zephir_array_update_string(&pzv, s, l, &tmp, PH_SEPARATE);
p = Z_ARRVAL(pzv);
if (re_update) {
wrap_tmp = 1;
} else {
p = Z_ARRVAL(tmp);
}
}
}
break;
case 'l':
ll = va_arg(ap, long);
if (zephir_array_isset_long_fetch(&fetched, &pzv, ll, 1)) {
if (Z_TYPE(fetched) == IS_ARRAY) {
if (i == (types_length - 1)) {
re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
zephir_array_update_long(&pzv, ll, value, PH_COPY | PH_SEPARATE ZEPHIR_DEBUG_PARAMS_DUMMY);
p = Z_ARRVAL(pzv);
} else {
re_update = !Z_REFCOUNTED(fetched) || (Z_REFCOUNT(fetched) > 1 && !Z_ISREF(fetched));
if (re_update) {
ZVAL_DUP(&tmp, &fetched);
zephir_array_update_long(&pzv, ll, &tmp, 0 ZEPHIR_DEBUG_PARAMS_DUMMY);
p = Z_ARRVAL(tmp);
} else {
p = Z_ARRVAL(fetched);
}
}
must_continue = 1;
}
}
if (!must_continue) {
ZVAL_ARR(&pzv, p);
re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
if (i == (types_length - 1)) {
zephir_array_update_long(&pzv, ll, value, PH_COPY | PH_SEPARATE ZEPHIR_DEBUG_PARAMS_DUMMY);
p = Z_ARRVAL(pzv);
} else {
array_init(&tmp);
zephir_array_update_long(&pzv, ll, &tmp, PH_SEPARATE ZEPHIR_DEBUG_PARAMS_DUMMY);
p = Z_ARRVAL(pzv);
if (re_update) {
wrap_tmp = 1;
} else {
p = Z_ARRVAL(tmp);
}
}
}
break;
case 'z':
item = va_arg(ap, zval*);
if (zephir_array_isset_fetch(&fetched, &pzv, item, 1)) {
if (Z_TYPE(fetched) == IS_ARRAY) {
if (i == (types_length - 1)) {
re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
zephir_array_update_zval(&pzv, item, value, PH_COPY | PH_SEPARATE);
p = Z_ARRVAL(pzv);
} else {
re_update = !Z_REFCOUNTED(fetched) || (Z_REFCOUNT(fetched) > 1 && !Z_ISREF(fetched));
if (re_update) {
ZVAL_DUP(&tmp, &fetched);
zephir_array_update_zval(&pzv, item, &tmp, 0);
p = Z_ARRVAL(tmp);
} else {
p = Z_ARRVAL(fetched);
}
}
must_continue = 1;
}
}
if (!must_continue) {
ZVAL_ARR(&pzv, p);
re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
if (i == (types_length - 1)) {
zephir_array_update_zval(&pzv, item, value, PH_COPY | PH_SEPARATE);
p = Z_ARRVAL(pzv);
} else {
array_init(&tmp);
zephir_array_update_zval(&pzv, item, &tmp, PH_SEPARATE);
p = Z_ARRVAL(pzv);
if (re_update) {
wrap_tmp = 1;
} else {
p = Z_ARRVAL(tmp);
}
}
}
break;
case 'a':
re_update = !Z_REFCOUNTED(pzv) || (Z_REFCOUNT(pzv) > 1 && !Z_ISREF(pzv));
if (re_update) {
zephir_array_append(&pzv, value, PH_COPY | PH_SEPARATE ZEPHIR_DEBUG_PARAMS_DUMMY);
} else {
zephir_array_append(&pzv, value, PH_COPY ZEPHIR_DEBUG_PARAMS_DUMMY);
}
p = Z_ARRVAL(pzv);
break;
}
}
}
int zephir_array_update_multi(zval *arr, zval *value, const char *types, int types_length, int types_count, ...)
{
va_list ap;
va_start(ap, types_count);
SEPARATE_ZVAL_IF_NOT_REF(arr);
zephir_array_update_multi_ex(arr, value, types, types_length, types_count, ap);
va_end(ap);
return 0;
}
/**
* Fast in_array function
*/
int zephir_fast_in_array(zval *value, zval *haystack)
{
zval *entry;
zend_ulong num_idx;
zend_string *str_idx;
if (Z_TYPE_P(haystack) != IS_ARRAY) {
return 0;
}
if (Z_TYPE_P(value) == IS_STRING) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(haystack), num_idx, str_idx, entry) {
if (fast_equal_check_string(value, entry)) {
return 1;
}
} ZEND_HASH_FOREACH_END();
} else {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(haystack), num_idx, str_idx, entry) {
if (fast_equal_check_function(value, entry)) {
return 1;
}
} ZEND_HASH_FOREACH_END();
}
return 0;
}
/**
* Fast array merge
*/
void zephir_fast_array_merge(zval *return_value, zval *array1, zval *array2)
{
int init_size, num;
if (Z_TYPE_P(array1) != IS_ARRAY) {
zend_error(E_WARNING, "First argument is not an array");
RETURN_NULL();
}
if (Z_TYPE_P(array2) != IS_ARRAY) {
zend_error(E_WARNING, "Second argument is not an array");
RETURN_NULL();
}
init_size = zend_hash_num_elements(Z_ARRVAL_P(array1));
num = zend_hash_num_elements(Z_ARRVAL_P(array2));
if (num > init_size) {
init_size = num;
}
array_init_size(return_value, init_size);
php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array1));
php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array2));
}