LCOV - code coverage report
Current view: top level - /ext - colopl_bc_php74.c (source / functions) Coverage Total Hit
Test: Extension code coverage Lines: 65.4 % 1165 762
Test Date: 2026-05-18 07:06:36 Functions: 72.2 % 97 70

            Line data    Source code
       1              : /*
       2              :   +----------------------------------------------------------------------+
       3              :   | COLOPL PHP Backwards Compatibility Extension.                        |
       4              :   +----------------------------------------------------------------------+
       5              :   | Copyright (c) COLOPL, Inc.                                           |
       6              :   +----------------------------------------------------------------------+
       7              :   | This source file is subject to the BSD-3-Clause license that is      |
       8              :   | bundled with this package in the file LICENSE.                       |
       9              :   +----------------------------------------------------------------------+
      10              :   | Author: Go Kudo <g-kudo@colopl.co.jp>                                |
      11              :   +----------------------------------------------------------------------+
      12              : */
      13              : 
      14              : #ifdef HAVE_CONFIG_H
      15              : # include "config.h"
      16              : #endif
      17              : 
      18              : #include "php_colopl_bc.h"
      19              : 
      20              : #include "ext/standard/php_array.h"
      21              : #include "ext/standard/php_string.h"
      22              : #include "zend_exceptions.h"
      23              : #include "zend_operators.h"
      24              : 
      25              : /* zend_operators.c */
      26              : 
      27              : #define COLOPL_BC_TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
      28              : 
      29              : typedef struct _php_colopl_bc_snapshot_context {
      30              :         HashTable arrays;
      31              :         HashTable objects;
      32              : } php_colopl_bc_snapshot_context;
      33              : 
      34              : typedef struct _php_colopl_bc_diagnostic_error_state {
      35              :         int error_reporting;
      36              :         int user_error_handler_error_reporting;
      37              :         bool record_errors;
      38              : } php_colopl_bc_diagnostic_error_state;
      39              : 
      40              : typedef struct _php_colopl_bc_user_sort_zero_pair {
      41              :         uint32_t first;
      42              :         uint32_t second;
      43              : } php_colopl_bc_user_sort_zero_pair;
      44              : 
      45              : typedef struct _php_colopl_bc_user_sort_context {
      46              :         php_colopl_bc_user_sort_zero_pair *zero_pairs;
      47              :         uint32_t zero_pair_count;
      48              :         uint32_t zero_pair_capacity;
      49              : } php_colopl_bc_user_sort_context;
      50              : 
      51        12096 : static inline void php_colopl_bc_snapshot_context_init(php_colopl_bc_snapshot_context *ctx)
      52              : {
      53        12096 :         zend_hash_init(&ctx->arrays, 8, NULL, NULL, 0);
      54        12096 :         zend_hash_init(&ctx->objects, 8, NULL, NULL, 0);
      55        12096 : }
      56              : 
      57        12096 : static inline void php_colopl_bc_snapshot_context_destroy(php_colopl_bc_snapshot_context *ctx)
      58              : {
      59        12096 :         zend_hash_destroy(&ctx->objects);
      60        12096 :         zend_hash_destroy(&ctx->arrays);
      61        12096 : }
      62              : 
      63        10120 : static inline void php_colopl_bc_diagnostic_error_state_suppress(php_colopl_bc_diagnostic_error_state *state)
      64              : {
      65        10120 :         state->error_reporting = EG(error_reporting);
      66        10120 :         state->user_error_handler_error_reporting = EG(user_error_handler_error_reporting);
      67        10120 :         state->record_errors = EG(record_errors);
      68              : 
      69        10120 :         EG(error_reporting) = 0;
      70        10120 :         EG(user_error_handler_error_reporting) = 0;
      71        10120 :         EG(record_errors) = false;
      72        10120 : }
      73              : 
      74        10120 : static inline void php_colopl_bc_diagnostic_error_state_restore(php_colopl_bc_diagnostic_error_state *state)
      75              : {
      76        10120 :         EG(record_errors) = state->record_errors;
      77        10120 :         EG(user_error_handler_error_reporting) = state->user_error_handler_error_reporting;
      78        10120 :         EG(error_reporting) = state->error_reporting;
      79        10120 : }
      80              : 
      81        10120 : static inline bool php_colopl_bc_clear_diagnostic_exception(void)
      82              : {
      83        10120 :         if (EG(exception)) {
      84            0 :                 zend_clear_exception();
      85              : 
      86            0 :                 return true;
      87              :         }
      88              : 
      89        10120 :         return false;
      90              : }
      91              : 
      92        27812 : static inline bool php_colopl_bc_zval_contains_object(zval *op, HashTable *seen_arrays)
      93              : {
      94              :         zend_array *array;
      95              :         zval *entry;
      96              : 
      97        27812 :         ZVAL_DEREF(op);
      98        27812 :         if (Z_TYPE_P(op) == IS_INDIRECT) {
      99            0 :                 op = Z_INDIRECT_P(op);
     100            0 :                 ZVAL_DEREF(op);
     101              :         }
     102              : 
     103        27812 :         switch (Z_TYPE_P(op)) {
     104         1900 :                 case IS_OBJECT:
     105         1900 :                         return true;
     106         1368 :                 case IS_ARRAY:
     107         1368 :                         array = Z_ARRVAL_P(op);
     108         1368 :                         if (zend_hash_index_exists(seen_arrays, (zend_ulong)(uintptr_t) array)) {
     109           44 :                                 return false;
     110              :                         }
     111         1324 :                         zend_hash_index_add_empty_element(seen_arrays, (zend_ulong)(uintptr_t) array);
     112              : 
     113         6232 :                         ZEND_HASH_FOREACH_VAL(array, entry) {
     114         4912 :                                 if (php_colopl_bc_zval_contains_object(entry, seen_arrays)) {
     115            4 :                                         return true;
     116              :                                 }
     117              :                         } ZEND_HASH_FOREACH_END();
     118              : 
     119         1320 :                         return false;
     120        24544 :                 default:
     121        24544 :                         return false;
     122              :         }
     123              : }
     124              : 
     125        11916 : static inline bool php_colopl_bc_zvals_contain_object(zval *op1, zval *op2)
     126              : {
     127              :         HashTable seen_arrays;
     128              :         bool contains_object;
     129              : 
     130        11916 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     131        11916 :         contains_object =
     132        22788 :                 php_colopl_bc_zval_contains_object(op1, &seen_arrays) ||
     133        10872 :                 php_colopl_bc_zval_contains_object(op2, &seen_arrays);
     134        11916 :         zend_hash_destroy(&seen_arrays);
     135              : 
     136        11916 :         return contains_object;
     137              : }
     138              : 
     139          108 : static inline bool php_colopl_bc_zval_contains_child_array(zval *op)
     140              : {
     141              :         zval *entry;
     142              : 
     143          108 :         ZVAL_DEREF(op);
     144          108 :         if (Z_TYPE_P(op) == IS_INDIRECT) {
     145            0 :                 op = Z_INDIRECT_P(op);
     146            0 :                 ZVAL_DEREF(op);
     147              :         }
     148              : 
     149          108 :         if (Z_TYPE_P(op) != IS_ARRAY) {
     150            0 :                 return false;
     151              :         }
     152              : 
     153         3192 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(op), entry) {
     154         3092 :                 ZVAL_DEREF(entry);
     155         3092 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     156            0 :                         entry = Z_INDIRECT_P(entry);
     157            0 :                         ZVAL_DEREF(entry);
     158              :                 }
     159         3092 :                 if (Z_TYPE_P(entry) == IS_ARRAY) {
     160            8 :                         return true;
     161              :                 }
     162              :         } ZEND_HASH_FOREACH_END();
     163              : 
     164          100 :         return false;
     165              : }
     166              : 
     167        24844 : static inline bool php_colopl_bc_zval_contains_recursive_array_ex(zval *op, HashTable *seen_arrays, HashTable *active_arrays)
     168              : {
     169              :         zend_array *array;
     170              :         zend_ulong key;
     171              :         zval *entry;
     172        24844 :         bool contains_recursive_array = false;
     173              : 
     174        24844 :         ZVAL_DEREF(op);
     175        24844 :         if (Z_TYPE_P(op) == IS_INDIRECT) {
     176            0 :                 op = Z_INDIRECT_P(op);
     177            0 :                 ZVAL_DEREF(op);
     178              :         }
     179              : 
     180        24844 :         if (Z_TYPE_P(op) != IS_ARRAY) {
     181        23624 :                 return false;
     182              :         }
     183              : 
     184         1220 :         array = Z_ARRVAL_P(op);
     185         1220 :         key = (zend_ulong)(uintptr_t) array;
     186         1220 :         if (zend_hash_index_exists(active_arrays, key)) {
     187            0 :                 return true;
     188              :         }
     189         1220 :         if (zend_hash_index_exists(seen_arrays, key)) {
     190           40 :                 return false;
     191              :         }
     192              : 
     193         1180 :         zend_hash_index_add_empty_element(active_arrays, key);
     194         5884 :         ZEND_HASH_FOREACH_VAL(array, entry) {
     195         4704 :                 if (php_colopl_bc_zval_contains_recursive_array_ex(entry, seen_arrays, active_arrays)) {
     196            0 :                         contains_recursive_array = true;
     197            0 :                         break;
     198              :                 }
     199              :         } ZEND_HASH_FOREACH_END();
     200         1180 :         zend_hash_index_del(active_arrays, key);
     201         1180 :         if (contains_recursive_array) {
     202            0 :                 return true;
     203              :         }
     204         1180 :         zend_hash_index_add_empty_element(seen_arrays, key);
     205              : 
     206         1180 :         return false;
     207              : }
     208              : 
     209          100 : static inline bool php_colopl_bc_zval_contains_recursive_array(zval *op)
     210              : {
     211              :         HashTable seen_arrays, active_arrays;
     212              :         bool contains_recursive_array;
     213              : 
     214          100 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     215          100 :         zend_hash_init(&active_arrays, 8, NULL, NULL, 0);
     216          100 :         contains_recursive_array = php_colopl_bc_zval_contains_recursive_array_ex(op, &seen_arrays, &active_arrays);
     217          100 :         zend_hash_destroy(&active_arrays);
     218          100 :         zend_hash_destroy(&seen_arrays);
     219              : 
     220          100 :         return contains_recursive_array;
     221              : }
     222              : 
     223        10020 : static inline bool php_colopl_bc_zvals_contain_recursive_array(zval *op1, zval *op2)
     224              : {
     225              :         HashTable seen_arrays, active_arrays;
     226              :         bool contains_recursive_array;
     227              : 
     228        10020 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     229        10020 :         zend_hash_init(&active_arrays, 8, NULL, NULL, 0);
     230        10020 :         contains_recursive_array =
     231        20040 :                 php_colopl_bc_zval_contains_recursive_array_ex(op1, &seen_arrays, &active_arrays) ||
     232        10020 :                 php_colopl_bc_zval_contains_recursive_array_ex(op2, &seen_arrays, &active_arrays);
     233        10020 :         zend_hash_destroy(&active_arrays);
     234        10020 :         zend_hash_destroy(&seen_arrays);
     235              : 
     236        10020 :         return contains_recursive_array;
     237              : }
     238              : 
     239        24844 : static inline bool php_colopl_bc_snapshot_zval(zval *dst, zval *src, php_colopl_bc_snapshot_context *ctx)
     240              : {
     241              :         zend_object *src_object, *object, *cached_obj;
     242              :         zend_array *src_array, *array, *cached_arr;
     243              :         zend_ulong num_key;
     244              :         zend_string *str_key;
     245              :         zval *entry, new_entry, *src_prop, *dst_prop;
     246              :         uint32_t i;
     247              :         ptrdiff_t offset;
     248              : 
     249        24844 :         ZVAL_DEREF(src);
     250              : 
     251        24844 :         switch (Z_TYPE_P(src)) {
     252         1220 :                 case IS_ARRAY: {
     253         1220 :                         src_array = Z_ARRVAL_P(src);
     254         1220 :                         cached_arr = zend_hash_index_find_ptr(&ctx->arrays, (zend_ulong)(uintptr_t) src_array);
     255         1220 :                         if (cached_arr != NULL) {
     256           40 :                                 GC_ADDREF(cached_arr);
     257           40 :                                 ZVAL_ARR(dst, cached_arr);
     258              : 
     259           40 :                                 return true;
     260              :                         }
     261              : 
     262         1180 :                         array = zend_new_array(zend_hash_num_elements(src_array));
     263         1180 :                         ZVAL_ARR(dst, array);
     264         1180 :                         zend_hash_index_update_ptr(&ctx->arrays, (zend_ulong)(uintptr_t) src_array, array);
     265              : 
     266         5884 :                         ZEND_HASH_FOREACH_KEY_VAL(src_array, num_key, str_key, entry) {
     267         4704 :                                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     268            0 :                                         entry = Z_INDIRECT_P(entry);
     269              :                                 }
     270              : 
     271         4704 :                                 if (!php_colopl_bc_snapshot_zval(&new_entry, entry, ctx)) {
     272            0 :                                         zval_ptr_dtor(dst);
     273            0 :                                         ZVAL_UNDEF(dst);
     274              : 
     275            0 :                                         return false;
     276              :                                 }
     277              : 
     278         4704 :                                 if (str_key) {
     279         2296 :                                         zend_hash_update(array, str_key, &new_entry);
     280              :                                 } else {
     281         2408 :                                         zend_hash_index_update(array, num_key, &new_entry);
     282              :                                 }
     283              :                         } ZEND_HASH_FOREACH_END();
     284              : 
     285         1180 :                         return true;
     286              :                 }
     287            0 :                 case IS_OBJECT: {
     288            0 :                         src_object = Z_OBJ_P(src);
     289            0 :                         cached_obj = zend_hash_index_find_ptr(&ctx->objects, (zend_ulong)(uintptr_t) src_object);
     290            0 :                         if (cached_obj != NULL) {
     291            0 :                                 GC_ADDREF(cached_obj);
     292            0 :                                 ZVAL_OBJ(dst, cached_obj);
     293              : 
     294            0 :                                 return true;
     295              :                         }
     296              : 
     297            0 :                         if (src_object->handlers != &std_object_handlers) {
     298            0 :                                 return false;
     299              :                         }
     300              : 
     301            0 :                         object = zend_objects_new(src_object->ce);
     302              : 
     303            0 :                         zend_object_store_ctor_failed(object);
     304            0 :                         ZVAL_OBJ(dst, object);
     305            0 :                         zend_hash_index_update_ptr(&ctx->objects, (zend_ulong)(uintptr_t) src_object, object);
     306              : 
     307            0 :                         for (i = 0; i < src_object->ce->default_properties_count; i++) {
     308            0 :                                 src_prop = src_object->properties_table + i;
     309            0 :                                 dst_prop = object->properties_table + i;
     310              : 
     311            0 :                                 ZVAL_UNDEF(dst_prop);
     312            0 :                                 Z_PROP_FLAG_P(dst_prop) = Z_PROP_FLAG_P(src_prop);
     313              : 
     314            0 :                                 if (Z_TYPE_P(src_prop) == IS_UNDEF) {
     315            0 :                                         continue;
     316              :                                 }
     317              : 
     318            0 :                                 if (!php_colopl_bc_snapshot_zval(dst_prop, src_prop, ctx)) {
     319            0 :                                         zval_ptr_dtor(dst);
     320            0 :                                         ZVAL_UNDEF(dst);
     321              : 
     322            0 :                                         return false;
     323              :                                 }
     324              : 
     325            0 :                                 Z_PROP_FLAG_P(dst_prop) = Z_PROP_FLAG_P(src_prop);
     326              :                         }
     327              : 
     328            0 :                         if (src_object->properties != NULL && zend_hash_num_elements(src_object->properties) > 0) {
     329            0 :                                 object->properties = zend_new_array(zend_hash_num_elements(src_object->properties));
     330            0 :                                 zend_hash_real_init_mixed(object->properties);
     331              : 
     332            0 :                                 ZEND_HASH_FOREACH_KEY_VAL(src_object->properties, num_key, str_key, entry) {
     333            0 :                                         if (Z_TYPE_P(entry) == IS_INDIRECT) {
     334            0 :                                                 offset = Z_INDIRECT_P(entry) - src_object->properties_table;
     335            0 :                                                 if (offset >= 0 && offset < src_object->ce->default_properties_count) {
     336            0 :                                                         ZVAL_INDIRECT(&new_entry, object->properties_table + offset);
     337              :                                                 } else {
     338            0 :                                                         entry = Z_INDIRECT_P(entry);
     339            0 :                                                         if (!php_colopl_bc_snapshot_zval(&new_entry, entry, ctx)) {
     340            0 :                                                                 zval_ptr_dtor(dst);
     341            0 :                                                                 ZVAL_UNDEF(dst);
     342              : 
     343            0 :                                                                 return false;
     344              :                                                         }
     345              :                                                 }
     346              :                                         } else {
     347            0 :                                                 if (!php_colopl_bc_snapshot_zval(&new_entry, entry, ctx)) {
     348            0 :                                                         zval_ptr_dtor(dst);
     349            0 :                                                         ZVAL_UNDEF(dst);
     350              : 
     351            0 :                                                         return false;
     352              :                                                 }
     353            0 :                                                 Z_PROP_FLAG_P(&new_entry) = Z_PROP_FLAG_P(entry);
     354              :                                         }
     355              : 
     356            0 :                                         if (str_key) {
     357            0 :                                                 zend_hash_update(object->properties, str_key, &new_entry);
     358              :                                         } else {
     359            0 :                                                 zend_hash_index_update(object->properties, num_key, &new_entry);
     360              :                                         }
     361              :                                 } ZEND_HASH_FOREACH_END();
     362              :                         }
     363              : 
     364            0 :                         return true;
     365              :                 }
     366        23624 :                 default:
     367        23624 :                         ZVAL_DUP(dst, src);
     368        23624 :                         return true;
     369              :         }
     370              : }
     371              : 
     372        80800 : static inline zval *php_colopl_bc_hash_get_ordered_value(HashTable *ht, uint32_t *pos, zend_ulong *num_key, zend_string **str_key)
     373              : {
     374              :         zval *value;
     375              :         Bucket *bucket;
     376              : 
     377        80800 :         if (HT_IS_PACKED(ht)) {
     378        55800 :                 while (*pos < ht->nNumUsed) {
     379              : #if PHP_VERSION_ID >= 80200
     380        55752 :                         value = ht->arPacked + *pos;
     381        55752 :                         *num_key = *pos;
     382              : #else
     383              :                         bucket = ht->arData + *pos;
     384              :                         value = &bucket->val;
     385              :                         *num_key = bucket->h;
     386              : #endif
     387        55752 :                         *str_key = NULL;
     388        55752 :                         (*pos)++;
     389        55752 :                         if (Z_TYPE_P(value) != IS_UNDEF) {
     390        55752 :                                 return value;
     391              :                         }
     392              :                 }
     393              :         } else {
     394        25000 :                 while (*pos < ht->nNumUsed) {
     395        24992 :                         bucket = ht->arData + *pos;
     396        24992 :                         (*pos)++;
     397        24992 :                         if (Z_TYPE(bucket->val) != IS_UNDEF) {
     398        24992 :                                 *num_key = bucket->h;
     399        24992 :                                 *str_key = bucket->key;
     400        24992 :                                 return &bucket->val;
     401              :                         }
     402              :                 }
     403              :         }
     404              : 
     405           56 :         return NULL;
     406              : }
     407              : 
     408           68 : static inline void php_colopl_bc_user_sort_context_init(php_colopl_bc_user_sort_context *ctx)
     409              : {
     410           68 :         ctx->zero_pairs = NULL;
     411           68 :         ctx->zero_pair_count = 0;
     412           68 :         ctx->zero_pair_capacity = 0;
     413           68 : }
     414              : 
     415           68 : static inline void php_colopl_bc_user_sort_context_destroy(php_colopl_bc_user_sort_context *ctx)
     416              : {
     417           68 :         if (ctx->zero_pairs != NULL) {
     418           64 :                 efree(ctx->zero_pairs);
     419              :         }
     420           68 : }
     421              : 
     422         7468 : static inline void php_colopl_bc_user_sort_context_record_zero_pair(Bucket *first, Bucket *second)
     423              : {
     424         7468 :         php_colopl_bc_user_sort_context *ctx = COLOPL_BC_G(php74_user_sort_context);
     425              :         uint32_t first_pos, second_pos, new_capacity;
     426              : 
     427         7468 :         if (ctx == NULL) {
     428          600 :                 return;
     429              :         }
     430              : 
     431         6868 :         first_pos = Z_EXTRA(first->val);
     432         6868 :         second_pos = Z_EXTRA(second->val);
     433         6868 :         if (first_pos == second_pos) {
     434            0 :                 return;
     435              :         }
     436              : 
     437         6868 :         if (ctx->zero_pair_count == ctx->zero_pair_capacity) {
     438          248 :                 new_capacity = ctx->zero_pair_capacity == 0 ? 16 : ctx->zero_pair_capacity * 2;
     439          248 :                 ctx->zero_pairs = erealloc(ctx->zero_pairs, sizeof(php_colopl_bc_user_sort_zero_pair) * new_capacity);
     440          248 :                 ctx->zero_pair_capacity = new_capacity;
     441              :         }
     442              : 
     443         6868 :         ctx->zero_pairs[ctx->zero_pair_count].first = first_pos;
     444         6868 :         ctx->zero_pairs[ctx->zero_pair_count].second = second_pos;
     445         6868 :         ctx->zero_pair_count++;
     446              : }
     447              : 
     448         2984 : static inline bool php_colopl_bc_hash_get_ordered_entry_at(HashTable *ht, uint32_t target_pos, zval **value, zend_ulong *num_key, zend_string **str_key)
     449              : {
     450         2984 :         uint32_t pos = 0, ordered_pos = 0;
     451              : 
     452        71464 :         while ((*value = php_colopl_bc_hash_get_ordered_value(ht, &pos, num_key, str_key)) != NULL) {
     453        71464 :                 if (ordered_pos == target_pos) {
     454         2984 :                         return true;
     455              :                 }
     456        68480 :                 ordered_pos++;
     457              :         }
     458              : 
     459            0 :         return false;
     460              : }
     461              : 
     462         1348 : static inline bool php_colopl_bc_user_sort_pair_values_identical(zval *original, uint32_t first_pos, uint32_t second_pos)
     463              : {
     464              :         zend_ulong first_num_key, second_num_key;
     465              :         zend_string *first_str_key, *second_str_key;
     466              :         zval *first, *second;
     467              : 
     468         1348 :         if (Z_ISUNDEF_P(original)) {
     469            0 :                 return false;
     470              :         }
     471              : 
     472         1348 :         if (!php_colopl_bc_hash_get_ordered_entry_at(Z_ARRVAL_P(original), first_pos, &first, &first_num_key, &first_str_key) ||
     473         1348 :                 !php_colopl_bc_hash_get_ordered_entry_at(Z_ARRVAL_P(original), second_pos, &second, &second_num_key, &second_str_key)) {
     474            0 :                 return false;
     475              :         }
     476              : 
     477         1348 :         return zend_is_identical(first, second);
     478              : }
     479              : 
     480          240 : static inline bool php_colopl_bc_user_sort_find_final_position_by_key(zval *legacy, zend_ulong original_num_key, zend_string *original_str_key, uint32_t *final_pos)
     481              : {
     482              :         zend_ulong num_key;
     483              :         zend_string *str_key;
     484              :         zval *value;
     485          240 :         uint32_t pos = 0;
     486              : 
     487          240 :         *final_pos = 0;
     488         5440 :         while ((value = php_colopl_bc_hash_get_ordered_value(Z_ARRVAL_P(legacy), &pos, &num_key, &str_key)) != NULL) {
     489              :                 (void) value;
     490              : 
     491         5440 :                 if (original_str_key != NULL) {
     492         2304 :                         if (str_key != NULL && zend_string_equals(str_key, original_str_key)) {
     493          144 :                                 return true;
     494              :                         }
     495         3136 :                 } else if (str_key == NULL && num_key == original_num_key) {
     496           96 :                         return true;
     497              :                 }
     498              : 
     499         5200 :                 (*final_pos)++;
     500              :         }
     501              : 
     502            0 :         return false;
     503              : }
     504              : 
     505           48 : static inline bool php_colopl_bc_user_sort_find_final_position_by_value(zval *legacy, zval *original_value, uint32_t *final_pos)
     506              : {
     507              :         zend_ulong num_key;
     508              :         zend_string *str_key;
     509              :         zval *value;
     510           48 :         uint32_t pos = 0;
     511              : 
     512           48 :         *final_pos = 0;
     513         1568 :         while ((value = php_colopl_bc_hash_get_ordered_value(Z_ARRVAL_P(legacy), &pos, &num_key, &str_key)) != NULL) {
     514              :                 (void) num_key;
     515              :                 (void) str_key;
     516              : 
     517         1568 :                 if (zend_is_identical(value, original_value)) {
     518           48 :                         return true;
     519              :                 }
     520              : 
     521         1520 :                 (*final_pos)++;
     522              :         }
     523              : 
     524            0 :         return false;
     525              : }
     526              : 
     527          288 : static inline bool php_colopl_bc_user_sort_find_final_position(zval *legacy, zval *original, uint32_t original_pos, bool renumber, uint32_t *final_pos)
     528              : {
     529              :         zend_ulong num_key;
     530              :         zend_string *str_key;
     531              :         zval *value;
     532              : 
     533          288 :         if (Z_ISUNDEF_P(original) ||
     534          288 :                 !php_colopl_bc_hash_get_ordered_entry_at(Z_ARRVAL_P(original), original_pos, &value, &num_key, &str_key)) {
     535            0 :                 return false;
     536              :         }
     537              : 
     538          288 :         if (renumber) {
     539           48 :                 return php_colopl_bc_user_sort_find_final_position_by_value(legacy, value, final_pos);
     540              :         }
     541              : 
     542          240 :         return php_colopl_bc_user_sort_find_final_position_by_key(legacy, num_key, str_key, final_pos);
     543              : }
     544              : 
     545           68 : static inline bool php_colopl_bc_user_sort_context_detect_incompatible_order(php_colopl_bc_user_sort_context *ctx, zval *legacy, zval *original, bool renumber)
     546              : {
     547              :         uint32_t num_elements, i, first_pos, second_pos, first_final_pos, second_final_pos;
     548              : 
     549           68 :         if (ctx->zero_pair_count == 0) {
     550            4 :                 return false;
     551              :         }
     552              : 
     553           64 :         num_elements = zend_hash_num_elements(Z_ARRVAL_P(legacy));
     554           64 :         if (num_elements == 0) {
     555            0 :                 return false;
     556              :         }
     557              : 
     558         1484 :         for (i = 0; i < ctx->zero_pair_count; i++) {
     559         1468 :                 first_pos = ctx->zero_pairs[i].first;
     560         1468 :                 second_pos = ctx->zero_pairs[i].second;
     561         1468 :                 if (first_pos >= num_elements || second_pos >= num_elements) {
     562            0 :                         continue;
     563              :                 }
     564              : 
     565         1468 :                 if (renumber && php_colopl_bc_user_sort_pair_values_identical(original, first_pos, second_pos)) {
     566         1324 :                         continue;
     567              :                 }
     568              : 
     569          144 :                 if (!php_colopl_bc_user_sort_find_final_position(legacy, original, first_pos, renumber, &first_final_pos) ||
     570          144 :                         !php_colopl_bc_user_sort_find_final_position(legacy, original, second_pos, renumber, &second_final_pos)) {
     571            0 :                         continue;
     572              :                 }
     573              : 
     574          144 :                 if ((first_pos < second_pos && first_final_pos > second_final_pos) ||
     575           48 :                         (first_pos > second_pos && first_final_pos < second_final_pos)) {
     576           48 :                         return true;
     577              :                 }
     578              :         }
     579              : 
     580           16 :         return false;
     581              : }
     582              : 
     583          100 : static inline bool php_colopl_bc_same_snapshot_array_pair_seen(HashTable *seen_arrays, zend_array *legacy_array, zend_array *native_array)
     584              : {
     585              :         uintptr_t pair[2];
     586              : 
     587          100 :         pair[0] = (uintptr_t) legacy_array;
     588          100 :         pair[1] = (uintptr_t) native_array;
     589              : 
     590          100 :         if (zend_hash_str_exists(seen_arrays, (char *) pair, sizeof(pair))) {
     591            0 :                 return true;
     592              :         }
     593          100 :         zend_hash_str_add_empty_element(seen_arrays, (char *) pair, sizeof(pair));
     594              : 
     595          100 :         return false;
     596              : }
     597              : 
     598         1172 : static inline bool php_colopl_bc_same_snapshot_value_ex(zval *legacy, zval *native, php_colopl_bc_snapshot_context *ctx, HashTable *seen_arrays)
     599              : {
     600              :         zend_object *snapshot;
     601              :         zend_array *legacy_array, *native_array;
     602              :         zend_ulong legacy_num_key, native_num_key;
     603              :         zend_string *legacy_str_key, *native_str_key;
     604              :         zval *legacy_value, *native_value;
     605              :         uint32_t legacy_pos, native_pos;
     606              : 
     607         1172 :         ZVAL_DEREF(legacy);
     608         1172 :         ZVAL_DEREF(native);
     609              : 
     610         1172 :         if (Z_TYPE_P(legacy) == IS_OBJECT && Z_TYPE_P(native) == IS_OBJECT) {
     611            0 :                 snapshot = zend_hash_index_find_ptr(&ctx->objects, (zend_ulong)(uintptr_t) Z_OBJ_P(legacy));
     612            0 :                 if (snapshot != NULL && snapshot == Z_OBJ_P(native)) {
     613            0 :                         return true;
     614              :                 }
     615              :         }
     616              : 
     617         1172 :         if (Z_TYPE_P(legacy) != IS_ARRAY || Z_TYPE_P(native) != IS_ARRAY) {
     618         1072 :                 return zend_is_identical(legacy, native);
     619              :         }
     620              : 
     621          100 :         legacy_array = Z_ARRVAL_P(legacy);
     622          100 :         native_array = Z_ARRVAL_P(native);
     623          100 :         if (php_colopl_bc_same_snapshot_array_pair_seen(seen_arrays, legacy_array, native_array)) {
     624            0 :                 return true;
     625              :         }
     626              : 
     627          100 :         if (zend_hash_num_elements(legacy_array) != zend_hash_num_elements(native_array)) {
     628            0 :                 return false;
     629              :         }
     630              : 
     631          100 :         legacy_pos = native_pos = 0;
     632         1164 :         while ((legacy_value = php_colopl_bc_hash_get_ordered_value(legacy_array, &legacy_pos, &legacy_num_key, &legacy_str_key)) != NULL) {
     633         1136 :                 native_value = php_colopl_bc_hash_get_ordered_value(native_array, &native_pos, &native_num_key, &native_str_key);
     634              : 
     635         1136 :                 if (native_value == NULL) {
     636            0 :                         return false;
     637              :                 }
     638              : 
     639         1136 :                 if (legacy_str_key != NULL || native_str_key != NULL) {
     640          436 :                         if (legacy_str_key == NULL || native_str_key == NULL) {
     641           64 :                                 return false;
     642              :                         }
     643          372 :                         if (!zend_string_equals(legacy_str_key, native_str_key)) {
     644            0 :                                 return false;
     645              :                         }
     646          700 :                 } else if (legacy_num_key != native_num_key) {
     647            0 :                         return false;
     648              :                 }
     649              : 
     650         1072 :                 if (!php_colopl_bc_same_snapshot_value_ex(legacy_value, native_value, ctx, seen_arrays)) {
     651            8 :                         return false;
     652              :                 }
     653              :         }
     654              : 
     655           28 :         return php_colopl_bc_hash_get_ordered_value(native_array, &native_pos, &native_num_key, &native_str_key) == NULL;
     656              : }
     657              : 
     658          100 : static inline bool php_colopl_bc_same_snapshot_value(zval *legacy, zval *native, php_colopl_bc_snapshot_context *ctx)
     659              : {
     660              :         HashTable seen_arrays;
     661              :         bool same;
     662              : 
     663          100 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     664          100 :         same = php_colopl_bc_same_snapshot_value_ex(legacy, native, ctx, &seen_arrays);
     665          100 :         zend_hash_destroy(&seen_arrays);
     666              : 
     667          100 :         return same;
     668              : }
     669              : 
     670            0 : static inline void php_colopl_bc_convert_object_to_type(zval *op, zval *dst, uint32_t ctype)
     671              : {
     672            0 :         ZVAL_UNDEF(dst);
     673            0 :         if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), dst, ctype) == FAILURE) {
     674            0 :                 zend_error(
     675              :                         E_WARNING,
     676              :                         "Object of class %s could not be converted to %s",
     677            0 :                         ZSTR_VAL(Z_OBJCE_P(op)->name),
     678              :                         zend_get_type_by_const(ctype)
     679              :                 );
     680              :         }
     681            0 : }
     682              : 
     683         7704 : static zend_never_inline zval* ZEND_FASTCALL _php_colopl_bc_zendi_convert_scalar_to_number_silent(zval *op, zval *holder)
     684              : {
     685         7704 :         switch (Z_TYPE_P(op)) {
     686            0 :                 case IS_NULL:
     687              :                 case IS_FALSE:
     688            0 :                         ZVAL_LONG(holder, 0);
     689            0 :                         return holder;
     690            0 :                 case IS_TRUE:
     691            0 :                         ZVAL_LONG(holder, 1);
     692            0 :                         return holder;
     693         3532 :                 case IS_STRING:
     694         3532 :                         if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), 1)) == 0) {
     695         1096 :                                 ZVAL_LONG(holder, 0);
     696              :                         }
     697         3532 :                         return holder;
     698            0 :                 case IS_RESOURCE:
     699            0 :                         ZVAL_LONG(holder, Z_RES_HANDLE_P(op));
     700            0 :                         return holder;
     701            0 :                 case IS_OBJECT:
     702            0 :                         php_colopl_bc_convert_object_to_type(op, holder, _IS_NUMBER);
     703            0 :                         if (UNEXPECTED(EG(exception)) ||
     704            0 :                                 UNEXPECTED(Z_TYPE_P(holder) != IS_LONG && Z_TYPE_P(holder) != IS_DOUBLE)) {
     705            0 :                                 ZVAL_LONG(holder, 1);
     706              :                         }
     707            0 :                         return holder;
     708         4172 :                 case IS_LONG:
     709              :                 case IS_DOUBLE:
     710              :                 default:
     711         4172 :                         return op;
     712              :         }
     713              : }
     714              : 
     715        15120 : static int legacy_compare_fast(zval *op1, zval *op2)
     716              : {
     717        15120 :         int converted = 0;
     718              :         zval op1_copy, op2_copy;
     719              : 
     720              :         while (1) {
     721        18972 :                 switch (COLOPL_BC_TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
     722         8880 :                         case COLOPL_BC_TYPE_PAIR(IS_LONG, IS_LONG):
     723         8880 :                                 return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
     724              : 
     725          200 :                         case COLOPL_BC_TYPE_PAIR(IS_DOUBLE, IS_LONG):
     726          200 :                                 return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - (double)Z_LVAL_P(op2));
     727              : 
     728          200 :                         case COLOPL_BC_TYPE_PAIR(IS_LONG, IS_DOUBLE):
     729          200 :                                 return ZEND_NORMALIZE_BOOL((double)Z_LVAL_P(op1) - Z_DVAL_P(op2));
     730              : 
     731           60 :                         case COLOPL_BC_TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
     732           60 :                                 if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
     733           60 :                                         return 0;
     734              :                                 } else {
     735            0 :                                         return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - Z_DVAL_P(op2));
     736              :                                 }
     737              : 
     738           80 :                         case COLOPL_BC_TYPE_PAIR(IS_ARRAY, IS_ARRAY):
     739           80 :                                 return zend_compare_arrays(op1, op2);
     740              : 
     741          100 :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_NULL):
     742              :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_FALSE):
     743              :                         case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_NULL):
     744              :                         case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_FALSE):
     745              :                         case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_TRUE):
     746          100 :                                 return 0;
     747              : 
     748           20 :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_TRUE):
     749           20 :                                 return -1;
     750              : 
     751           20 :                         case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_NULL):
     752           20 :                                 return 1;
     753              : 
     754           60 :                         case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_OBJECT):
     755           60 :                                 return zval_is_true(op2) ? 0 : 1;
     756              : 
     757           60 :                         case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_OBJECT):
     758           60 :                                 return zval_is_true(op2) ? -1 : 0;
     759              : 
     760           60 :                         case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_TRUE):
     761           60 :                                 return zval_is_true(op1) ? 0 : -1;
     762              : 
     763           60 :                         case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_FALSE):
     764           60 :                                 return zval_is_true(op1) ? 1 : 0;
     765              : 
     766         1584 :                         case COLOPL_BC_TYPE_PAIR(IS_STRING, IS_STRING):
     767         1584 :                                 if (Z_STR_P(op1) == Z_STR_P(op2)) {
     768          772 :                                         return 0;
     769              :                                 }
     770          812 :                                 return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
     771              : 
     772          100 :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_STRING):
     773          100 :                                 return Z_STRLEN_P(op2) == 0 ? 0 : -1;
     774              : 
     775          100 :                         case COLOPL_BC_TYPE_PAIR(IS_STRING, IS_NULL):
     776          100 :                                 return Z_STRLEN_P(op1) == 0 ? 0 : 1;
     777              : 
     778           60 :                         case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_NULL):
     779           60 :                                 return 1;
     780              : 
     781           60 :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_OBJECT):
     782           60 :                                 return -1;
     783              : 
     784         7268 :                         default:
     785         7268 :                                 if (Z_ISREF_P(op1)) {
     786            0 :                                         op1 = Z_REFVAL_P(op1);
     787            0 :                                         continue;
     788         7268 :                                 } else if (Z_ISREF_P(op2)) {
     789            0 :                                         op2 = Z_REFVAL_P(op2);
     790            0 :                                         continue;
     791              :                                 }
     792              : 
     793         7268 :                                 if (Z_TYPE_P(op1) == IS_OBJECT
     794          864 :                                  && Z_TYPE_P(op2) == IS_OBJECT
     795          180 :                                  && Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
     796           60 :                                         return 0;
     797         7208 :                                 } else if (Z_TYPE_P(op1) == IS_OBJECT) {
     798          804 :                                         return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
     799         6404 :                                 } else if (Z_TYPE_P(op2) == IS_OBJECT) {
     800          672 :                                         return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
     801              :                                 }
     802              : 
     803         5732 :                                 if (!converted) {
     804         5012 :                                         if (Z_TYPE_P(op1) < IS_TRUE) {
     805          360 :                                                 return zval_is_true(op2) ? -1 : 0;
     806         4652 :                                         } else if (Z_TYPE_P(op1) == IS_TRUE) {
     807          240 :                                                 return zval_is_true(op2) ? 0 : 1;
     808         4412 :                                         } else if (Z_TYPE_P(op2) < IS_TRUE) {
     809          340 :                                                 return zval_is_true(op1) ? 1 : 0;
     810         4072 :                                         } else if (Z_TYPE_P(op2) == IS_TRUE) {
     811          220 :                                                 return zval_is_true(op1) ? 0 : -1;
     812              :                                         } else {
     813         3852 :                                                 op1 = _php_colopl_bc_zendi_convert_scalar_to_number_silent(op1, &op1_copy);
     814         3852 :                                                 op2 = _php_colopl_bc_zendi_convert_scalar_to_number_silent(op2, &op2_copy);
     815         3852 :                                                 if (EG(exception)) {
     816            0 :                                                         return 1; /* to stop comparison of arrays */
     817              :                                                 }
     818         3852 :                                                 converted = 1;
     819              :                                         }
     820          720 :                                 } else if (Z_TYPE_P(op1)==IS_ARRAY) {
     821          360 :                                         return 1;
     822          360 :                                 } else if (Z_TYPE_P(op2)==IS_ARRAY) {
     823          360 :                                         return -1;
     824              :                                 } else {
     825            0 :                                         ZEND_UNREACHABLE();
     826              :                                         zend_throw_error(NULL, "Unsupported operand types");
     827              :                                         return 1;
     828              :                                 }
     829              :                 }
     830              :         }
     831              : }
     832              : 
     833        11916 : static int legacy_compare_slow(zval *op1, zval *op2)
     834              : {
     835              :         php_colopl_bc_snapshot_context snapshot_context;
     836              :         php_colopl_bc_diagnostic_error_state error_state;
     837              :         zval native_op1, native_op2;
     838              :         bool have_native_snapshot, native_failed;
     839              :         int bc, native;
     840              : 
     841        11916 :         if (COLOPL_BC_G(php74_compare_mode) <= COLOPL_BC_PHP74_COMPARE_MODE_SILENT) {
     842            0 :                 return legacy_compare_fast(op1, op2);
     843              :         }
     844              : 
     845        11916 :         ZVAL_UNDEF(&native_op1);
     846        11916 :         ZVAL_UNDEF(&native_op2);
     847        11916 :         php_colopl_bc_snapshot_context_init(&snapshot_context);
     848        11916 :         have_native_snapshot = !php_colopl_bc_zvals_contain_object(op1, op2) &&
     849        20040 :                 !php_colopl_bc_zvals_contain_recursive_array(op1, op2) &&
     850        31956 :                 php_colopl_bc_snapshot_zval(&native_op1, op1, &snapshot_context) &&
     851        10020 :                 php_colopl_bc_snapshot_zval(&native_op2, op2, &snapshot_context)
     852              :         ;
     853              : 
     854        11916 :         bc = legacy_compare_fast(op1, op2);
     855              : 
     856        11916 :         if (have_native_snapshot && !EG(exception)) {
     857        10020 :                 php_colopl_bc_diagnostic_error_state_suppress(&error_state);
     858        10020 :                 native = zend_compare(&native_op1, &native_op2);
     859        10020 :                 native_failed = php_colopl_bc_clear_diagnostic_exception();
     860        10020 :                 php_colopl_bc_diagnostic_error_state_restore(&error_state);
     861              :         } else {
     862         1896 :                 native = bc;
     863         1896 :                 native_failed = false;
     864              :         }
     865              : 
     866        11916 :         if (have_native_snapshot && !native_failed && native != bc) {
     867          812 :                 if (COLOPL_BC_G(php74_compare_mode) & COLOPL_BC_PHP74_COMPARE_MODE_LOG) {
     868          808 :                         php_log_err_with_severity("Incompatible compare detected", LOG_NOTICE);
     869              :                 }
     870          812 :                 if (COLOPL_BC_G(php74_compare_mode) & COLOPL_BC_PHP74_COMPARE_MODE_DEPRECATED) {
     871          808 :                         php_error_docref(NULL, E_DEPRECATED, "Incompatible compare detected");
     872              :                 }
     873              :         }
     874              : 
     875        11916 :         if (!Z_ISUNDEF(native_op2)) {
     876        10020 :                 zval_ptr_dtor(&native_op2);
     877              :         }
     878              : 
     879        11916 :         if (!Z_ISUNDEF(native_op1)) {
     880        10020 :                 zval_ptr_dtor(&native_op1);
     881              :         }
     882              : 
     883        11916 :         php_colopl_bc_snapshot_context_destroy(&snapshot_context);
     884              : 
     885        11916 :         return bc;
     886              : }
     887              : 
     888          258 : PHP_INI_MH(OnUpdateCompareMode)
     889              : {
     890          258 :         if (OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
     891            0 :                 return FAILURE;
     892              :         }
     893              : 
     894          258 :         if (COLOPL_BC_G(php74_compare_mode) <= COLOPL_BC_PHP74_COMPARE_MODE_SILENT) {
     895          162 :                 COLOPL_BC_G(php74_compare_func) = legacy_compare_fast;
     896              :         } else {
     897           96 :                 COLOPL_BC_G(php74_compare_func) = legacy_compare_slow;
     898              :         }
     899              : 
     900          258 :         return SUCCESS;
     901              : }
     902              : 
     903        15120 : int php_colopl_bc_compare(zval *op1, zval *op2)
     904              : {
     905        15120 :         return COLOPL_BC_G(php74_compare_func)(op1, op2);
     906              : }
     907              : 
     908            0 : static zend_always_inline bool php_colopl_bc_fast_equal_check_long(zval *op1, zval *op2)
     909              : {
     910            0 :         if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
     911            0 :                 return Z_LVAL_P(op1) == Z_LVAL_P(op2);
     912              :         }
     913            0 :         return php_colopl_bc_compare(op1, op2) == 0;
     914              : }
     915              : 
     916            8 : static zend_always_inline bool php_colopl_bc_fast_equal_check_string(zval *op1, zval *op2)
     917              : {
     918            8 :         if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
     919            0 :                 return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));
     920              :         }
     921            8 :         return php_colopl_bc_compare(op1, op2) == 0;
     922              : }
     923              : 
     924            8 : static zend_always_inline bool php_colopl_bc_fast_equal_check_function(zval *op1, zval *op2)
     925              : {
     926            8 :         if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
     927            0 :                 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
     928            0 :                         return Z_LVAL_P(op1) == Z_LVAL_P(op2);
     929            0 :                 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
     930            0 :                         return ((double)Z_LVAL_P(op1)) == Z_DVAL_P(op2);
     931              :                 }
     932            8 :         } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
     933            0 :                 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
     934            0 :                         return Z_DVAL_P(op1) == Z_DVAL_P(op2);
     935            0 :                 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
     936            0 :                         return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2));
     937              :                 }
     938            8 :         } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
     939            8 :                 if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
     940            4 :                         return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));
     941              :                 }
     942              :         }
     943            4 :         return php_colopl_bc_compare(op1, op2) == 0;
     944              : }
     945              : 
     946              : /* array.c */
     947              : 
     948         2792 : static int php_colopl_bc_array_key_compare(Bucket *f, Bucket *s)
     949              : {
     950              :         zend_uchar t;
     951              :         zend_long l1, l2;
     952              :         double d;
     953              : 
     954         2792 :         if (f->key == NULL) {
     955           40 :                 if (s->key == NULL) {
     956            0 :                         return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
     957              :                 } else {
     958           40 :                         l1 = (zend_long)f->h;
     959           40 :                         t = is_numeric_string(s->key->val, s->key->len, &l2, &d, 1);
     960           40 :                         if (t == IS_LONG) {
     961              :                                 /* pass */
     962           40 :                         } else if (t == IS_DOUBLE) {
     963            0 :                                 return ZEND_NORMALIZE_BOOL((double)l1 - d);
     964              :                         } else {
     965           40 :                                 l2 = 0;
     966              :                         }
     967              :                 }
     968              :         } else {
     969         2752 :                 if (s->key) {
     970         2704 :                         return zendi_smart_strcmp(f->key, s->key);
     971              :                 } else {
     972           48 :                         l2 = (zend_long)s->h;
     973           48 :                         t = is_numeric_string(f->key->val, f->key->len, &l1, &d, 1);
     974           48 :                         if (t == IS_LONG) {
     975              :                                 /* pass */
     976           48 :                         } else if (t == IS_DOUBLE) {
     977            0 :                                 return ZEND_NORMALIZE_BOOL(d - (double)l2);
     978              :                         } else {
     979           48 :                                 l1 = 0;
     980              :                         }
     981              :                 }
     982              :         }
     983           88 :         return ZEND_NORMALIZE_BOOL(l1 - l2);
     984              : }
     985              : 
     986         1412 : static int php_colopl_bc_array_reverse_key_compare(Bucket *a, Bucket *b)
     987              : {
     988         1412 :         return php_colopl_bc_array_key_compare(b, a);
     989              : }
     990              : 
     991            0 : static int php_colopl_bc_array_key_compare_numeric(Bucket *f, Bucket *s)
     992              : {
     993            0 :         if (f->key == NULL && s->key == NULL) {
     994            0 :                 return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
     995              :         } else {
     996              :                 double d1, d2;
     997            0 :                 if (f->key) {
     998            0 :                         d1 = zend_strtod(f->key->val, NULL);
     999              :                 } else {
    1000            0 :                         d1 = (double)(zend_long)f->h;
    1001              :                 }
    1002            0 :                 if (s->key) {
    1003            0 :                         d2 = zend_strtod(s->key->val, NULL);
    1004              :                 } else {
    1005            0 :                         d2 = (double)(zend_long)s->h;
    1006              :                 }
    1007            0 :                 return ZEND_NORMALIZE_BOOL(d1 - d2);
    1008              :         }
    1009              : }
    1010              : 
    1011            0 : static int php_colopl_bc_array_reverse_key_compare_numeric(Bucket *a, Bucket *b)
    1012              : {
    1013            0 :         return php_colopl_bc_array_key_compare_numeric(b, a);
    1014              : }
    1015              : 
    1016            0 : static int php_colopl_bc_array_key_compare_string_case(Bucket *f, Bucket *s)
    1017              : {
    1018              :         const char *s1, *s2;
    1019              :         size_t l1, l2;
    1020              :         char buf1[MAX_LENGTH_OF_LONG + 1];
    1021              :         char buf2[MAX_LENGTH_OF_LONG + 1];
    1022              : 
    1023            0 :         if (f->key) {
    1024            0 :                 s1 = f->key->val;
    1025            0 :                 l1 = f->key->len;
    1026              :         } else {
    1027            0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
    1028            0 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
    1029              :         }
    1030            0 :         if (s->key) {
    1031            0 :                 s2 = s->key->val;
    1032            0 :                 l2 = s->key->len;
    1033              :         } else {
    1034            0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
    1035            0 :                 l2 = buf2 + sizeof(buf2) - 1 - s1;
    1036              :         }
    1037            0 :         return zend_binary_strcasecmp_l(s1, l1, s2, l2);
    1038              : }
    1039              : 
    1040            0 : static int php_colopl_bc_array_reverse_key_compare_string_case(Bucket *a, Bucket *b)
    1041              : {
    1042            0 :         return php_colopl_bc_array_key_compare_string_case(b, a);
    1043              : }
    1044              : 
    1045            0 : static int php_colopl_bc_array_key_compare_string(Bucket *f, Bucket *s)
    1046              : {
    1047              :         const char *s1, *s2;
    1048              :         size_t l1, l2;
    1049              :         char buf1[MAX_LENGTH_OF_LONG + 1];
    1050              :         char buf2[MAX_LENGTH_OF_LONG + 1];
    1051              : 
    1052            0 :         if (f->key) {
    1053            0 :                 s1 = f->key->val;
    1054            0 :                 l1 = f->key->len;
    1055              :         } else {
    1056            0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
    1057            0 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
    1058              :         }
    1059            0 :         if (s->key) {
    1060            0 :                 s2 = s->key->val;
    1061            0 :                 l2 = s->key->len;
    1062              :         } else {
    1063            0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
    1064            0 :                 l2 = buf2 + sizeof(buf2) - 1 - s2;
    1065              :         }
    1066            0 :         return zend_binary_strcmp(s1, l1, s2, l2);
    1067              : }
    1068              : 
    1069            0 : static int php_colopl_bc_array_reverse_key_compare_string(Bucket *a, Bucket *b)
    1070              : {
    1071            0 :         return php_colopl_bc_array_key_compare_string(b, a);
    1072              : }
    1073              : 
    1074            0 : static int php_colopl_bc_array_key_compare_string_natural_general(Bucket *f, Bucket *s, int fold_case)
    1075              : {
    1076              :         const char *s1, *s2;
    1077              :         size_t l1, l2;
    1078              :         char buf1[MAX_LENGTH_OF_LONG + 1];
    1079              :         char buf2[MAX_LENGTH_OF_LONG + 1];
    1080              : 
    1081            0 :         if (f->key) {
    1082            0 :                 s1 = f->key->val;
    1083            0 :                 l1 = f->key->len;
    1084              :         } else {
    1085            0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
    1086            0 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
    1087              :         }
    1088            0 :         if (s->key) {
    1089            0 :                 s2 = s->key->val;
    1090            0 :                 l2 = s->key->len;
    1091              :         } else {
    1092            0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
    1093            0 :                 l2 = buf2 + sizeof(buf2) - 1 - s1;
    1094              :         }
    1095            0 :         return strnatcmp_ex(s1, l1, s2, l2, fold_case);
    1096              : }
    1097              : 
    1098            0 : static int php_colopl_bc_array_key_compare_string_natural_case(Bucket *a, Bucket *b)
    1099              : {
    1100            0 :         return php_colopl_bc_array_key_compare_string_natural_general(a, b, 1);
    1101              : }
    1102              : 
    1103            0 : static int php_colopl_bc_array_reverse_key_compare_string_natural_case(Bucket *a, Bucket *b)
    1104              : {
    1105            0 :         return php_colopl_bc_array_key_compare_string_natural_general(b, a, 1);
    1106              : }
    1107              : 
    1108            0 : static int php_colopl_bc_array_key_compare_string_natural(Bucket *a, Bucket *b)
    1109              : {
    1110            0 :         return php_colopl_bc_array_key_compare_string_natural_general(a, b, 0);
    1111              : }
    1112              : 
    1113            0 : static int php_colopl_bc_array_reverse_key_compare_string_natural(Bucket *a, Bucket *b)
    1114              : {
    1115            0 :         return php_colopl_bc_array_key_compare_string_natural_general(b, a, 0);
    1116              : }
    1117              : 
    1118            0 : static int php_colopl_bc_array_key_compare_string_locale(Bucket *f, Bucket *s)
    1119              : {
    1120              :         const char *s1, *s2;
    1121              :         char buf1[MAX_LENGTH_OF_LONG + 1];
    1122              :         char buf2[MAX_LENGTH_OF_LONG + 1];
    1123              : 
    1124            0 :         if (f->key) {
    1125            0 :                 s1 = f->key->val;
    1126              :         } else {
    1127            0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
    1128              :         }
    1129            0 :         if (s->key) {
    1130            0 :                 s2 = s->key->val;
    1131              :         } else {
    1132            0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
    1133              :         }
    1134            0 :         return strcoll(s1, s2);
    1135              : }
    1136              : 
    1137            0 : static int php_colopl_bc_array_reverse_key_compare_string_locale(Bucket *a, Bucket *b)
    1138              : {
    1139            0 :         return php_colopl_bc_array_key_compare_string_locale(b, a);
    1140              : }
    1141              : 
    1142         9276 : static int php_colopl_bc_array_data_compare(Bucket *f, Bucket *s)
    1143              : {
    1144         9276 :         zval *first = &f->val;
    1145         9276 :         zval *second = &s->val;
    1146              : 
    1147         9276 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1148            0 :                 first = Z_INDIRECT_P(first);
    1149              :         }
    1150         9276 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1151            0 :                 second = Z_INDIRECT_P(second);
    1152              :         }
    1153              : 
    1154         9276 :         return php_colopl_bc_compare(first, second);
    1155              : }
    1156              : 
    1157         3120 : static int php_colopl_bc_array_reverse_data_compare(Bucket *a, Bucket *b)
    1158              : {
    1159         3120 :         return php_colopl_bc_array_data_compare(a, b) * -1;
    1160              : }
    1161              : 
    1162            0 : static int php_colopl_bc_array_data_compare_numeric(Bucket *f, Bucket *s)
    1163              : {
    1164            0 :         zval *first = &f->val;
    1165            0 :         zval *second = &s->val;
    1166              : 
    1167            0 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1168            0 :                 first = Z_INDIRECT_P(first);
    1169              :         }
    1170            0 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1171            0 :                 second = Z_INDIRECT_P(second);
    1172              :         }
    1173              : 
    1174            0 :         return numeric_compare_function(first, second);
    1175              : }
    1176              : 
    1177            0 : static int php_colopl_bc_array_reverse_data_compare_numeric(Bucket *a, Bucket *b)
    1178              : {
    1179            0 :         return php_colopl_bc_array_data_compare_numeric(b, a);
    1180              : }
    1181              : 
    1182            0 : static int php_colopl_bc_array_data_compare_string_case(Bucket *f, Bucket *s)
    1183              : {
    1184            0 :         zval *first = &f->val;
    1185            0 :         zval *second = &s->val;
    1186              : 
    1187            0 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1188            0 :                 first = Z_INDIRECT_P(first);
    1189              :         }
    1190            0 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1191            0 :                 second = Z_INDIRECT_P(second);
    1192              :         }
    1193              : 
    1194            0 :         return string_case_compare_function(first, second);
    1195              : }
    1196              : 
    1197            0 : static int php_colopl_bc_array_reverse_data_compare_string_case(Bucket *a, Bucket *b)
    1198              : {
    1199            0 :         return php_colopl_bc_array_data_compare_string_case(b, a);
    1200              : }
    1201              : 
    1202            8 : static int php_colopl_bc_array_data_compare_string(Bucket *f, Bucket *s)
    1203              : {
    1204            8 :         zval *first = &f->val;
    1205            8 :         zval *second = &s->val;
    1206              : 
    1207            8 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1208            0 :                 first = Z_INDIRECT_P(first);
    1209              :         }
    1210            8 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1211            0 :                 second = Z_INDIRECT_P(second);
    1212              :         }
    1213              : 
    1214            8 :         return string_compare_function(first, second);
    1215              : }
    1216              : 
    1217            0 : static int php_colopl_bc_array_reverse_data_compare_string(Bucket *a, Bucket *b)
    1218              : {
    1219            0 :         return php_colopl_bc_array_data_compare_string(b, a);
    1220              : }
    1221              : 
    1222            0 : static int php_colopl_bc_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case)
    1223              : {
    1224              :         zend_string *tmp_str1, *tmp_str2;
    1225            0 :         zend_string *str1 = zval_get_tmp_string(&f->val, &tmp_str1);
    1226            0 :         zend_string *str2 = zval_get_tmp_string(&s->val, &tmp_str2);
    1227              : 
    1228            0 :         int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
    1229              : 
    1230            0 :         zend_tmp_string_release(tmp_str1);
    1231            0 :         zend_tmp_string_release(tmp_str2);
    1232            0 :         return result;
    1233              : }
    1234              : 
    1235            0 : static int php_colopl_bc_array_natural_compare(Bucket *a, Bucket *b)
    1236              : {
    1237            0 :         return php_colopl_bc_array_natural_general_compare(a, b, 0);
    1238              : }
    1239              : 
    1240            0 : static int php_colopl_bc_array_reverse_natural_compare(Bucket *a, Bucket *b)
    1241              : {
    1242            0 :         return php_colopl_bc_array_natural_general_compare(b, a, 0);
    1243              : }
    1244              : 
    1245            0 : static int php_colopl_bc_array_natural_case_compare(Bucket *a, Bucket *b)
    1246              : {
    1247            0 :         return php_colopl_bc_array_natural_general_compare(a, b, 1);
    1248              : }
    1249              : 
    1250            0 : static int php_colopl_bc_array_reverse_natural_case_compare(Bucket *a, Bucket *b)
    1251              : {
    1252            0 :         return php_colopl_bc_array_natural_general_compare(b, a, 1);
    1253              : }
    1254              : 
    1255            0 : static int php_colopl_bc_array_data_compare_string_locale(Bucket *f, Bucket *s)
    1256              : {
    1257            0 :         zval *first = &f->val;
    1258            0 :         zval *second = &s->val;
    1259              : 
    1260            0 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1261            0 :                 first = Z_INDIRECT_P(first);
    1262              :         }
    1263            0 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1264            0 :                 second = Z_INDIRECT_P(second);
    1265              :         }
    1266              : 
    1267            0 :         return string_locale_compare_function(first, second);
    1268              : }
    1269              : 
    1270            0 : static int php_colopl_bc_array_reverse_data_compare_string_locale(Bucket *a, Bucket *b)
    1271              : {
    1272            0 :         return php_colopl_bc_array_data_compare_string_locale(b, a);
    1273              : }
    1274              : 
    1275         5224 : static int php_colopl_bc_array_user_compare(Bucket *f, Bucket *s)
    1276              : {
    1277              :         zend_long ret;
    1278              :         zval args[2], retval;
    1279              :         int result;
    1280              : 
    1281         5224 :         ZVAL_COPY(&args[0], &f->val);
    1282         5224 :         ZVAL_COPY(&args[1], &s->val);
    1283              : 
    1284         5224 :         COLOPL_BC_G(user_compare_fci).param_count = 2;
    1285         5224 :         COLOPL_BC_G(user_compare_fci).params = args;
    1286         5224 :         COLOPL_BC_G(user_compare_fci).retval = &retval;
    1287         5224 :         if (zend_call_function(&COLOPL_BC_G(user_compare_fci), &COLOPL_BC_G(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    1288         5224 :                 ret = zval_get_long(&retval);
    1289         5224 :                 result = ZEND_NORMALIZE_BOOL(ret);
    1290              : 
    1291         5224 :                 zval_ptr_dtor(&retval);
    1292         5224 :                 zval_ptr_dtor(&args[1]);
    1293         5224 :                 zval_ptr_dtor(&args[0]);
    1294         5224 :                 if (result == 0) {
    1295         5220 :                         php_colopl_bc_user_sort_context_record_zero_pair(f, s);
    1296              :                 }
    1297              : 
    1298         5224 :                 return result;
    1299              :         } else {
    1300            0 :                 zval_ptr_dtor(&args[1]);
    1301            0 :                 zval_ptr_dtor(&args[0]);
    1302            0 :                 php_colopl_bc_user_sort_context_record_zero_pair(f, s);
    1303              : 
    1304            0 :                 result = 0;
    1305              :         }
    1306              : 
    1307            0 :         return result;
    1308              : }
    1309              : 
    1310         2248 : static int php_colopl_bc_array_user_key_compare(Bucket *f, Bucket *s)
    1311              : {
    1312              :         zval args[2];
    1313              :         zval retval;
    1314              :         zend_long result;
    1315              : 
    1316         2248 :         if (f->key == NULL) {
    1317         1464 :                 ZVAL_LONG(&args[0], f->h);
    1318              :         } else {
    1319          784 :                 ZVAL_STR_COPY(&args[0], f->key);
    1320              :         }
    1321         2248 :         if (s->key == NULL) {
    1322         1464 :                 ZVAL_LONG(&args[1], s->h);
    1323              :         } else {
    1324          784 :                 ZVAL_STR_COPY(&args[1], s->key);
    1325              :         }
    1326              : 
    1327         2248 :         COLOPL_BC_G(user_compare_fci).param_count = 2;
    1328         2248 :         COLOPL_BC_G(user_compare_fci).params = args;
    1329         2248 :         COLOPL_BC_G(user_compare_fci).retval = &retval;;
    1330         2248 :         if (zend_call_function(&COLOPL_BC_G(user_compare_fci), &COLOPL_BC_G(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    1331         2248 :                 result = zval_get_long(&retval);
    1332         2248 :                 zval_ptr_dtor(&retval);
    1333              :         } else {
    1334            0 :                 result = 0;
    1335              :         }
    1336              : 
    1337         2248 :         zval_ptr_dtor(&args[0]);
    1338         2248 :         zval_ptr_dtor(&args[1]);
    1339              : 
    1340         2248 :         result = ZEND_NORMALIZE_BOOL(result);
    1341         2248 :         if (result == 0) {
    1342         2248 :                 php_colopl_bc_user_sort_context_record_zero_pair(f, s);
    1343              :         }
    1344              : 
    1345         2248 :         return result;
    1346              : }
    1347              : 
    1348           44 : static bucket_compare_func_t php_colopl_bc_get_key_compare_func(zend_long sort_type, int reverse)
    1349              : {
    1350           44 :         switch (sort_type & ~PHP_SORT_FLAG_CASE) {
    1351            0 :                 case PHP_SORT_NUMERIC:
    1352            0 :                         if (reverse) {
    1353            0 :                                 return php_colopl_bc_array_reverse_key_compare_numeric;
    1354              :                         } else {
    1355            0 :                                 return php_colopl_bc_array_key_compare_numeric;
    1356              :                         }
    1357              :                         break;
    1358              : 
    1359            0 :                 case PHP_SORT_STRING:
    1360            0 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
    1361            0 :                                 if (reverse) {
    1362            0 :                                         return php_colopl_bc_array_reverse_key_compare_string_case;
    1363              :                                 } else {
    1364            0 :                                         return php_colopl_bc_array_key_compare_string_case;
    1365              :                                 }
    1366              :                         } else {
    1367            0 :                                 if (reverse) {
    1368            0 :                                         return php_colopl_bc_array_reverse_key_compare_string;
    1369              :                                 } else {
    1370            0 :                                         return php_colopl_bc_array_key_compare_string;
    1371              :                                 }
    1372              :                         }
    1373              :                         break;
    1374              : 
    1375            0 :                 case PHP_SORT_NATURAL:
    1376            0 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
    1377            0 :                                 if (reverse) {
    1378            0 :                                         return php_colopl_bc_array_reverse_key_compare_string_natural_case;
    1379              :                                 } else {
    1380            0 :                                         return php_colopl_bc_array_key_compare_string_natural_case;
    1381              :                                 }
    1382              :                         } else {
    1383            0 :                                 if (reverse) {
    1384            0 :                                         return php_colopl_bc_array_reverse_key_compare_string_natural;
    1385              :                                 } else {
    1386            0 :                                         return php_colopl_bc_array_key_compare_string_natural;
    1387              :                                 }
    1388              :                         }
    1389              :                         break;
    1390              : 
    1391            0 :                 case PHP_SORT_LOCALE_STRING:
    1392            0 :                         if (reverse) {
    1393            0 :                                 return php_colopl_bc_array_reverse_key_compare_string_locale;
    1394              :                         } else {
    1395            0 :                                 return php_colopl_bc_array_key_compare_string_locale;
    1396              :                         }
    1397              :                         break;
    1398              : 
    1399           44 :                 case PHP_SORT_REGULAR:
    1400              :                 default:
    1401           44 :                         if (reverse) {
    1402           24 :                                 return php_colopl_bc_array_reverse_key_compare;
    1403              :                         } else {
    1404           20 :                                 return php_colopl_bc_array_key_compare;
    1405              :                         }
    1406              :                         break;
    1407              :         }
    1408              :         return NULL;
    1409              : }
    1410              : 
    1411          100 : static bucket_compare_func_t php_colopl_bc_get_data_compare_func(zend_long sort_type, int reverse)
    1412              : {
    1413          100 :         switch (sort_type & ~PHP_SORT_FLAG_CASE) {
    1414            0 :                 case PHP_SORT_NUMERIC:
    1415            0 :                         if (reverse) {
    1416            0 :                                 return php_colopl_bc_array_reverse_data_compare_numeric;
    1417              :                         } else {
    1418            0 :                                 return php_colopl_bc_array_data_compare_numeric;
    1419              :                         }
    1420              :                         break;
    1421              : 
    1422            8 :                 case PHP_SORT_STRING:
    1423            8 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
    1424            0 :                                 if (reverse) {
    1425            0 :                                         return php_colopl_bc_array_reverse_data_compare_string_case;
    1426              :                                 } else {
    1427            0 :                                         return php_colopl_bc_array_data_compare_string_case;
    1428              :                                 }
    1429              :                         } else {
    1430            8 :                                 if (reverse) {
    1431            0 :                                         return php_colopl_bc_array_reverse_data_compare_string;
    1432              :                                 } else {
    1433            8 :                                         return php_colopl_bc_array_data_compare_string;
    1434              :                                 }
    1435              :                         }
    1436              :                         break;
    1437              : 
    1438            0 :                 case PHP_SORT_NATURAL:
    1439            0 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
    1440            0 :                                 if (reverse) {
    1441            0 :                                         return php_colopl_bc_array_reverse_natural_case_compare;
    1442              :                                 } else {
    1443            0 :                                         return php_colopl_bc_array_natural_case_compare;
    1444              :                                 }
    1445              :                         } else {
    1446            0 :                                 if (reverse) {
    1447            0 :                                         return php_colopl_bc_array_reverse_natural_compare;
    1448              :                                 } else {
    1449            0 :                                         return php_colopl_bc_array_natural_compare;
    1450              :                                 }
    1451              :                         }
    1452              :                         break;
    1453              : 
    1454            0 :                 case PHP_SORT_LOCALE_STRING:
    1455            0 :                         if (reverse) {
    1456            0 :                                 return php_colopl_bc_array_reverse_data_compare_string_locale;
    1457              :                         } else {
    1458            0 :                                 return php_colopl_bc_array_data_compare_string_locale;
    1459              :                         }
    1460              :                         break;
    1461              : 
    1462           92 :                 case PHP_SORT_REGULAR:
    1463              :                 default:
    1464           92 :                         if (reverse) {
    1465           40 :                                 return php_colopl_bc_array_reverse_data_compare;
    1466              :                         } else {
    1467           52 :                                 return php_colopl_bc_array_data_compare;
    1468              :                         }
    1469              :                         break;
    1470              :         }
    1471              :         return NULL;
    1472              : }
    1473              : 
    1474              : #define COLOPL_BC_MULTISORT_ORDER       0
    1475              : #define COLOPL_BC_MULTISORT_TYPE        1
    1476              : #define COLOPL_BC_MULTISORT_LAST        2
    1477              : 
    1478         1496 : int php_colopl_bc_multisort_compare(const void *a, const void *b)
    1479              : {
    1480         1496 :         Bucket *ab = *(Bucket **)a;
    1481         1496 :         Bucket *bb = *(Bucket **)b;
    1482              :         int r;
    1483              :         zend_long result;
    1484              : 
    1485         1496 :         r = 0;
    1486              :         do {
    1487         2992 :                 result = COLOPL_BC_G(multisort_func)[r](&ab[r], &bb[r]);
    1488         2992 :                 if (result != 0) {
    1489            0 :                         return result > 0 ? 1 : -1;
    1490              :                 }
    1491         2992 :                 r++;
    1492         2992 :         } while (Z_TYPE(ab[r].val) != IS_UNDEF);
    1493              : 
    1494         1496 :         return 0;
    1495              : }
    1496              : 
    1497              : #define COLOPL_BC_MULTISORT_ABORT       \
    1498              :         efree(func);    \
    1499              :         efree(arrays);  \
    1500              :         return;
    1501              : 
    1502          596 : static void colopl_bc_array_bucket_p_swap(void *p, void *q)
    1503              : {
    1504              :         Bucket *t;
    1505          596 :         Bucket **f = (Bucket **)p;
    1506          596 :         Bucket **g = (Bucket **)q;
    1507              : 
    1508          596 :         t = *f;
    1509          596 :         *f = *g;
    1510          596 :         *g = t;
    1511          596 : }
    1512              : 
    1513            8 : static inline void php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
    1514              : {
    1515              :         zval *value,                            /* value to check for */
    1516              :                  *array,                                /* array to check in */
    1517              :                  *entry;                                /* pointer to array entry */
    1518              :         zend_ulong num_idx;
    1519              :         zend_string *str_idx;
    1520            8 :         bool strict = 0;                        /* strict comparison or not */
    1521              : 
    1522            8 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1523            8 :                 Z_PARAM_ZVAL(value)
    1524            8 :                 Z_PARAM_ARRAY(array)
    1525            8 :                 Z_PARAM_OPTIONAL
    1526            8 :                 Z_PARAM_BOOL(strict)
    1527            8 :         ZEND_PARSE_PARAMETERS_END();
    1528              : 
    1529            8 :         if (strict) {
    1530            0 :                 if (Z_TYPE_P(value) == IS_LONG) {
    1531            0 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1532            0 :                                 ZVAL_DEREF(entry);
    1533            0 :                                 if (Z_TYPE_P(entry) == IS_LONG && Z_LVAL_P(entry) == Z_LVAL_P(value)) {
    1534            0 :                                         if (behavior == 0) {
    1535            0 :                                                 RETURN_TRUE;
    1536              :                                         } else {
    1537            0 :                                                 if (str_idx) {
    1538            0 :                                                         RETURN_STR_COPY(str_idx);
    1539              :                                                 } else {
    1540            0 :                                                         RETURN_LONG(num_idx);
    1541              :                                                 }
    1542              :                                         }
    1543              :                                 }
    1544              :                         } ZEND_HASH_FOREACH_END();
    1545              :                 } else {
    1546            0 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1547            0 :                                 ZVAL_DEREF(entry);
    1548            0 :                                 if (fast_is_identical_function(value, entry)) {
    1549            0 :                                         if (behavior == 0) {
    1550            0 :                                                 RETURN_TRUE;
    1551              :                                         } else {
    1552            0 :                                                 if (str_idx) {
    1553            0 :                                                         RETURN_STR_COPY(str_idx);
    1554              :                                                 } else {
    1555            0 :                                                         RETURN_LONG(num_idx);
    1556              :                                                 }
    1557              :                                         }
    1558              :                                 }
    1559              :                         } ZEND_HASH_FOREACH_END();
    1560              :                 }
    1561              :         } else {
    1562            8 :                 if (Z_TYPE_P(value) == IS_LONG) {
    1563            0 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1564            0 :                                 if (php_colopl_bc_fast_equal_check_long(value, entry)) {
    1565            0 :                                         if (behavior == 0) {
    1566            0 :                                                 RETURN_TRUE;
    1567              :                                         } else {
    1568            0 :                                                 if (str_idx) {
    1569            0 :                                                         RETURN_STR_COPY(str_idx);
    1570              :                                                 } else {
    1571            0 :                                                         RETURN_LONG(num_idx);
    1572              :                                                 }
    1573              :                                         }
    1574              :                                 }
    1575              :                         } ZEND_HASH_FOREACH_END();
    1576            8 :                 } else if (Z_TYPE_P(value) == IS_STRING) {
    1577            8 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1578            8 :                                 if (php_colopl_bc_fast_equal_check_string(value, entry)) {
    1579            8 :                                         if (behavior == 0) {
    1580            4 :                                                 RETURN_TRUE;
    1581              :                                         } else {
    1582            4 :                                                 if (str_idx) {
    1583            4 :                                                         RETURN_STR_COPY(str_idx);
    1584              :                                                 } else {
    1585            0 :                                                         RETURN_LONG(num_idx);
    1586              :                                                 }
    1587              :                                         }
    1588              :                                 }
    1589              :                         } ZEND_HASH_FOREACH_END();
    1590              :                 } else {
    1591            0 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1592            0 :                                 if (php_colopl_bc_fast_equal_check_function(value, entry)) {
    1593            0 :                                         if (behavior == 0) {
    1594            0 :                                                 RETURN_TRUE;
    1595              :                                         } else {
    1596            0 :                                                 if (str_idx) {
    1597            0 :                                                         RETURN_STR_COPY(str_idx);
    1598              :                                                 } else {
    1599            0 :                                                         RETURN_LONG(num_idx);
    1600              :                                                 }
    1601              :                                         }
    1602              :                                 }
    1603              :                         } ZEND_HASH_FOREACH_END();
    1604              :                 }
    1605              :         }
    1606              : 
    1607            0 :         RETURN_FALSE;
    1608              : }
    1609              : 
    1610              : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_VARS \
    1611              :         zend_fcall_info old_user_compare_fci; \
    1612              :         zend_fcall_info_cache old_user_compare_fci_cache \
    1613              : 
    1614              : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_BACKUP() \
    1615              :         old_user_compare_fci = COLOPL_BC_G(user_compare_fci); \
    1616              :         old_user_compare_fci_cache = COLOPL_BC_G(user_compare_fci_cache); \
    1617              :         COLOPL_BC_G(user_compare_fci_cache) = empty_fcall_info_cache; \
    1618              : 
    1619              : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE() \
    1620              :         zend_release_fcall_info_cache(&COLOPL_BC_G(user_compare_fci_cache)); \
    1621              :         COLOPL_BC_G(user_compare_fci) = old_user_compare_fci; \
    1622              :         COLOPL_BC_G(user_compare_fci_cache) = old_user_compare_fci_cache; \
    1623              : 
    1624          120 : static inline void php_colopl_bc_report_incompatible_sort(void)
    1625              : {
    1626          120 :         if (COLOPL_BC_G(php74_sort_mode) & COLOPL_BC_PHP74_SORT_MODE_LOG) {
    1627           96 :                 php_log_err_with_severity("Incompatible sort detected", LOG_NOTICE);
    1628              :         }
    1629              : 
    1630          120 :         if (COLOPL_BC_G(php74_sort_mode) & COLOPL_BC_PHP74_SORT_MODE_DEPRECATED) {
    1631           96 :                 php_error_docref(NULL, E_DEPRECATED, "Incompatible sort detected");
    1632              :         }
    1633          120 : }
    1634              : 
    1635          216 : static inline void php_colopl_bc_hash_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber, bool compare_func_may_call_user_code)
    1636              : {
    1637              :         (void) compare_func_may_call_user_code;
    1638              : 
    1639          216 :         zend_hash_sort_ex(ht, zend_sort, compare_func, renumber);
    1640          216 : }
    1641              : 
    1642          216 : static void legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAMETERS, zval *array, bucket_compare_func_t compare_func, bool renumber, bool compare_func_may_call_user_code)
    1643              : {
    1644          216 :         php_colopl_bc_hash_sort(Z_ARRVAL_P(array), compare_func, renumber, compare_func_may_call_user_code);
    1645          216 : }
    1646              : 
    1647          180 : static void legacy_hash_sort_slow(INTERNAL_FUNCTION_PARAMETERS, zval *array, bucket_compare_func_t compare_func, bool renumber, bool compare_func_may_call_user_code)
    1648              : {
    1649              :         php_colopl_bc_snapshot_context snapshot_context;
    1650              :         php_colopl_bc_diagnostic_error_state error_state;
    1651              :         php_colopl_bc_user_sort_context user_sort_context, *old_user_sort_context;
    1652              :         zend_internal_function *fn;
    1653              :         zval legacy, native, original, user_sort_original;
    1654              :         HashTable seen_arrays;
    1655          180 :         bool have_native_snapshot, native_failed = false,
    1656          180 :                 may_call_user_code = compare_func_may_call_user_code, track_user_sort = compare_func_may_call_user_code,
    1657          180 :                 user_sort_incompatible = false;
    1658              :         char *fnname_ptr;
    1659              : 
    1660          180 :         if (COLOPL_BC_G(php74_sort_mode) <= COLOPL_BC_PHP74_SORT_MODE_SILENT) {
    1661            0 :                 legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, compare_func, renumber, compare_func_may_call_user_code);
    1662            0 :                 return;
    1663              :         }
    1664              : 
    1665          180 :         ZVAL_UNDEF(&native);
    1666          180 :         ZVAL_UNDEF(&user_sort_original);
    1667          180 :         ZVAL_DUP(&legacy, array);
    1668          180 :         php_colopl_bc_snapshot_context_init(&snapshot_context);
    1669              : 
    1670          180 :         if (!may_call_user_code) {
    1671          112 :                 zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
    1672          112 :                 may_call_user_code = php_colopl_bc_zval_contains_object(array, &seen_arrays);
    1673          112 :                 zend_hash_destroy(&seen_arrays);
    1674              :         }
    1675              : 
    1676          180 :         if (!may_call_user_code) {
    1677          108 :                 may_call_user_code = php_colopl_bc_zval_contains_child_array(array);
    1678              :         }
    1679              : 
    1680          180 :         if (!may_call_user_code) {
    1681          100 :                 may_call_user_code = php_colopl_bc_zval_contains_recursive_array(array);
    1682              :         }
    1683              : 
    1684          180 :         have_native_snapshot = !may_call_user_code && php_colopl_bc_snapshot_zval(&native, array, &snapshot_context);
    1685              : 
    1686          180 :         if (track_user_sort) {
    1687           68 :                 ZVAL_DUP(&user_sort_original, array);
    1688           68 :                 SEPARATE_ARRAY(&user_sort_original);
    1689           68 :                 php_colopl_bc_user_sort_context_init(&user_sort_context);
    1690           68 :                 old_user_sort_context = COLOPL_BC_G(php74_user_sort_context);
    1691           68 :                 COLOPL_BC_G(php74_user_sort_context) = &user_sort_context;
    1692              :         }
    1693              : 
    1694          180 :         legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAM_PASSTHRU, &legacy, compare_func, renumber, compare_func_may_call_user_code);
    1695              : 
    1696          180 :         if (track_user_sort) {
    1697           68 :                 COLOPL_BC_G(php74_user_sort_context) = old_user_sort_context;
    1698           68 :                 if (!EG(exception)) {
    1699           68 :                         user_sort_incompatible = php_colopl_bc_user_sort_context_detect_incompatible_order(&user_sort_context, &legacy, &user_sort_original, renumber);
    1700              :                 }
    1701           68 :                 php_colopl_bc_user_sort_context_destroy(&user_sort_context);
    1702           68 :                 if (!Z_ISUNDEF(user_sort_original)) {
    1703           68 :                         zval_ptr_dtor(&user_sort_original);
    1704              :                 }
    1705              :         }
    1706              : 
    1707              :         /* Get native PHP bundled (internal) function ptr */
    1708          180 :         fnname_ptr = execute_data->func->internal_function.function_name->val;
    1709              :         /*
    1710              :          * Extracting last piece of namespaces, they're always identical a native function name
    1711              :          *
    1712              :          * e.g.)
    1713              :          * Colopl\ColoplBc\Php74\*****
    1714              :          *                       ^^^^^
    1715              :          */
    1716         4140 :         while (strchr(fnname_ptr, '\\')) {
    1717         3960 :                 ++fnname_ptr;
    1718              :         }
    1719          180 :         fn = zend_hash_str_find_ptr(EG(function_table), fnname_ptr, strlen(fnname_ptr));
    1720          180 :         if (EXPECTED(fn != NULL) && have_native_snapshot && !EG(exception)) {
    1721          100 :                 ZVAL_COPY_VALUE(&original, array);
    1722          100 :                 ZVAL_COPY_VALUE(array, &native);
    1723              : 
    1724          100 :                 php_colopl_bc_diagnostic_error_state_suppress(&error_state);
    1725          100 :                 fn->handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
    1726          100 :                 native_failed = php_colopl_bc_clear_diagnostic_exception();
    1727          100 :                 php_colopl_bc_diagnostic_error_state_restore(&error_state);
    1728          100 :                 ZVAL_COPY_VALUE(&native, array);
    1729          100 :                 ZVAL_COPY_VALUE(array, &original);
    1730              : 
    1731          100 :                 if (!native_failed && !php_colopl_bc_same_snapshot_value(&legacy, &native, &snapshot_context)) {
    1732           72 :                         php_colopl_bc_report_incompatible_sort();
    1733              :                 }
    1734              :         }
    1735              : 
    1736          180 :         if (user_sort_incompatible && !EG(exception)) {
    1737           48 :                 php_colopl_bc_report_incompatible_sort();
    1738              :         }
    1739              : 
    1740          180 :         if (!Z_ISUNDEF(native)) {
    1741          100 :                 zval_ptr_dtor(&native);
    1742              :         }
    1743              : 
    1744          180 :         php_colopl_bc_snapshot_context_destroy(&snapshot_context);
    1745              : 
    1746          180 :         zval_ptr_dtor(array);
    1747          180 :         ZVAL_ARR(array, Z_ARRVAL(legacy));
    1748              : }
    1749              : 
    1750          258 : PHP_INI_MH(OnUpdateSortMode)
    1751              : {
    1752          258 :         if (OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
    1753            0 :                 return FAILURE;
    1754              :         }
    1755              : 
    1756          258 :         if (COLOPL_BC_G(php74_sort_mode) <= 0) {
    1757          142 :                 COLOPL_BC_G(php74_hash_sort_func) = legacy_hash_sort_fast;
    1758              :         } else {
    1759          116 :                 COLOPL_BC_G(php74_hash_sort_func) = legacy_hash_sort_slow;
    1760              :         }
    1761              : 
    1762          258 :         return SUCCESS;
    1763              : }
    1764              : 
    1765           80 : static void php_colopl_bc_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compare_func, zend_bool renumber)
    1766              : {
    1767              :         zval *array, arr;
    1768              :         PHP_COLOPL_BC_ARRAY_CMP_FUNC_VARS;
    1769              : 
    1770           80 :         PHP_COLOPL_BC_ARRAY_CMP_FUNC_BACKUP();
    1771              : 
    1772           80 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    1773           80 :                 Z_PARAM_ARRAY_EX2(array, 0, 1, 0)
    1774           80 :                 Z_PARAM_FUNC(COLOPL_BC_G(user_compare_fci), COLOPL_BC_G(user_compare_fci_cache))
    1775           80 :         ZEND_PARSE_PARAMETERS_END_EX( PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE(); return );
    1776              : 
    1777           80 :         if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
    1778            0 :                 PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE();
    1779            0 :                 RETURN_TRUE;
    1780              :         }
    1781              : 
    1782           80 :         if (COLOPL_BC_G(php74_sort_mode) <= COLOPL_BC_PHP74_SORT_MODE_SILENT) {
    1783           12 :                 SEPARATE_ARRAY(array);
    1784           12 :                 legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, compare_func, renumber, true);
    1785           12 :                 PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE();
    1786           12 :                 RETURN_TRUE;
    1787              :         }
    1788              : 
    1789              :         /* Copy array, so the diagnostic path can compare the legacy result. */
    1790           68 :         ZVAL_DUP(&arr, array);
    1791              : 
    1792           68 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, &arr, compare_func, renumber, true);
    1793              : 
    1794           68 :         zval_ptr_dtor(array);
    1795           68 :         ZVAL_ARR(array, Z_ARRVAL(arr));
    1796              : 
    1797           68 :         PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE();
    1798           68 :         RETURN_TRUE;
    1799              : }
    1800              : 
    1801           20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_ksort)
    1802              : {
    1803              :         zval *array;
    1804           20 :         zend_long sort_type = PHP_SORT_REGULAR;
    1805              :         bucket_compare_func_t cmp;
    1806              : 
    1807           20 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1808           20 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    1809           20 :                 Z_PARAM_OPTIONAL
    1810           20 :                 Z_PARAM_LONG(sort_type)
    1811           20 :         ZEND_PARSE_PARAMETERS_END();
    1812              : 
    1813           20 :         cmp = php_colopl_bc_get_key_compare_func(sort_type, 0);
    1814              : 
    1815           20 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0, false);
    1816              : 
    1817           20 :         RETURN_TRUE;
    1818              : }
    1819              : 
    1820           24 : PHP_FUNCTION(Colopl_ColoplBc_Php74_krsort)
    1821              : {
    1822              :         zval *array;
    1823           24 :         zend_long sort_type = PHP_SORT_REGULAR;
    1824              :         bucket_compare_func_t cmp;
    1825              : 
    1826           24 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1827           24 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    1828           24 :                 Z_PARAM_OPTIONAL
    1829           24 :                 Z_PARAM_LONG(sort_type)
    1830           24 :         ZEND_PARSE_PARAMETERS_END();
    1831              : 
    1832           24 :         cmp = php_colopl_bc_get_key_compare_func(sort_type, 1);
    1833              : 
    1834           24 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0, false);
    1835              : 
    1836           24 :         RETURN_TRUE;
    1837              : }
    1838              : 
    1839           20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_asort)
    1840              : {
    1841              :         zval *array;
    1842           20 :         zend_long sort_type = PHP_SORT_REGULAR;
    1843              :         bucket_compare_func_t cmp;
    1844              : 
    1845           20 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1846           20 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    1847           20 :                 Z_PARAM_OPTIONAL
    1848           20 :                 Z_PARAM_LONG(sort_type)
    1849           20 :         ZEND_PARSE_PARAMETERS_END();
    1850              : 
    1851           20 :         cmp = php_colopl_bc_get_data_compare_func(sort_type, 0);
    1852              : 
    1853           20 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0, false);
    1854              : 
    1855           20 :         RETURN_TRUE;
    1856              : }
    1857              : 
    1858           20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_arsort)
    1859              : {
    1860              :         zval *array;
    1861           20 :         zend_long sort_type = PHP_SORT_REGULAR;
    1862              :         bucket_compare_func_t cmp;
    1863              : 
    1864           20 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1865           20 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    1866           20 :                 Z_PARAM_OPTIONAL
    1867           20 :                 Z_PARAM_LONG(sort_type)
    1868           20 :         ZEND_PARSE_PARAMETERS_END();
    1869              : 
    1870           20 :         cmp = php_colopl_bc_get_data_compare_func(sort_type, 1);
    1871              : 
    1872           20 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0, false);
    1873              : 
    1874           20 :         RETURN_TRUE;
    1875              : }
    1876              : 
    1877           32 : PHP_FUNCTION(Colopl_ColoplBc_Php74_sort)
    1878              : {
    1879              :         zval *array;
    1880           32 :         zend_long sort_type = PHP_SORT_REGULAR;
    1881              :         bucket_compare_func_t cmp;
    1882              : 
    1883           32 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1884           32 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    1885           32 :                 Z_PARAM_OPTIONAL
    1886           32 :                 Z_PARAM_LONG(sort_type)
    1887           32 :         ZEND_PARSE_PARAMETERS_END();
    1888              : 
    1889           32 :         cmp = php_colopl_bc_get_data_compare_func(sort_type, 0);
    1890              : 
    1891           32 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 1, false);
    1892              : 
    1893           32 :         RETURN_TRUE;
    1894              : }
    1895              : 
    1896           20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_rsort)
    1897              : {
    1898              :         zval *array;
    1899           20 :         zend_long sort_type = PHP_SORT_REGULAR;
    1900              :         bucket_compare_func_t cmp;
    1901              : 
    1902           20 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1903           20 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    1904           20 :                 Z_PARAM_OPTIONAL
    1905           20 :                 Z_PARAM_LONG(sort_type)
    1906           20 :         ZEND_PARSE_PARAMETERS_END();
    1907              : 
    1908           20 :         cmp = php_colopl_bc_get_data_compare_func(sort_type, 1);
    1909              : 
    1910           20 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 1, false);
    1911              : 
    1912           20 :         RETURN_TRUE;
    1913              : }
    1914              : 
    1915           32 : PHP_FUNCTION(Colopl_ColoplBc_Php74_usort)
    1916              : {
    1917           32 :         php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_compare, 1);
    1918           32 : }
    1919              : 
    1920           24 : PHP_FUNCTION(Colopl_ColoplBc_Php74_uasort)
    1921              : {
    1922           24 :         php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_compare, 0);
    1923           24 : }
    1924              : 
    1925           24 : PHP_FUNCTION(Colopl_ColoplBc_Php74_uksort)
    1926              : {
    1927           24 :         php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_key_compare, 0);
    1928           24 : }
    1929              : 
    1930            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_in_array)
    1931              : {
    1932            4 :         php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1933            4 : }
    1934              : 
    1935            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_search)
    1936              : {
    1937            4 :         php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1938            4 : }
    1939              : 
    1940            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_keys)
    1941              : {
    1942              :         zval *input,                            /* Input array */
    1943            4 :                  *search_value = NULL,  /* Value to search for */
    1944              :                  *entry,                                /* An entry in the input array */
    1945              :                  new_val;                               /* New value */
    1946            4 :         bool strict = 0;                        /* do strict comparison */
    1947              :         zend_ulong num_idx;
    1948              :         zend_string *str_idx;
    1949              :         zend_array *arrval;
    1950              :         zend_ulong elem_count;
    1951              : 
    1952            4 :         ZEND_PARSE_PARAMETERS_START(1, 3)
    1953            4 :                 Z_PARAM_ARRAY(input)
    1954            4 :                 Z_PARAM_OPTIONAL
    1955            4 :                 Z_PARAM_ZVAL(search_value)
    1956            4 :                 Z_PARAM_BOOL(strict)
    1957            4 :         ZEND_PARSE_PARAMETERS_END();
    1958            4 :         arrval = Z_ARRVAL_P(input);
    1959            4 :         elem_count = zend_hash_num_elements(arrval);
    1960              : 
    1961              :         /* Base case: empty input */
    1962            4 :         if (!elem_count) {
    1963            0 :                 RETURN_COPY(input);
    1964              :         }
    1965              : 
    1966              :         /* Initialize return array */
    1967            4 :         if (search_value != NULL) {
    1968            4 :                 array_init(return_value);
    1969              : 
    1970            4 :                 if (strict) {
    1971            0 :                         ZEND_HASH_FOREACH_KEY_VAL(arrval, num_idx, str_idx, entry) {
    1972            0 :                                 ZVAL_DEREF(entry);
    1973            0 :                                 if (fast_is_identical_function(search_value, entry)) {
    1974            0 :                                         if (str_idx) {
    1975            0 :                                                 ZVAL_STR_COPY(&new_val, str_idx);
    1976              :                                         } else {
    1977            0 :                                                 ZVAL_LONG(&new_val, num_idx);
    1978              :                                         }
    1979            0 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
    1980              :                                 }
    1981              :                         } ZEND_HASH_FOREACH_END();
    1982              :                 } else {
    1983           12 :                         ZEND_HASH_FOREACH_KEY_VAL(arrval, num_idx, str_idx, entry) {
    1984            8 :                                 if (php_colopl_bc_fast_equal_check_function(search_value, entry)) {
    1985            8 :                                         if (str_idx) {
    1986            8 :                                                 ZVAL_STR_COPY(&new_val, str_idx);
    1987              :                                         } else {
    1988            0 :                                                 ZVAL_LONG(&new_val, num_idx);
    1989              :                                         }
    1990            8 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
    1991              :                                 }
    1992              :                         } ZEND_HASH_FOREACH_END();
    1993              :                 }
    1994              :         } else {
    1995            0 :                 array_init_size(return_value, elem_count);
    1996            0 :                 zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
    1997            0 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    1998            0 :                         if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval)) {
    1999              :                                 /* Optimistic case: range(0..n-1) for vector-like packed array */
    2000            0 :                                 zend_ulong lval = 0;
    2001              : 
    2002            0 :                                 for (; lval < elem_count; ++lval) {
    2003            0 :                                         ZEND_HASH_FILL_SET_LONG(lval);
    2004            0 :                                         ZEND_HASH_FILL_NEXT();
    2005              :                                 }
    2006              :                         } else {
    2007              :                                 /* Go through input array and add keys to the return array */
    2008            0 :                                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
    2009            0 :                                         if (str_idx) {
    2010            0 :                                                 ZEND_HASH_FILL_SET_STR_COPY(str_idx);
    2011              :                                         } else {
    2012            0 :                                                 ZEND_HASH_FILL_SET_LONG(num_idx);
    2013              :                                         }
    2014            0 :                                         ZEND_HASH_FILL_NEXT();
    2015              :                                 } ZEND_HASH_FOREACH_END();
    2016              :                         }
    2017            0 :                 } ZEND_HASH_FILL_END();
    2018              :         }
    2019              : }
    2020              : 
    2021              : #if PHP_VERSION_ID < 80200
    2022              : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_multisort)
    2023              : {
    2024              :         zval*                   args;
    2025              :         zval**                  arrays;
    2026              :         Bucket**                indirect;
    2027              :         uint32_t                idx;
    2028              :         Bucket*                 p;
    2029              :         HashTable*              hash;
    2030              :         int                             argc;
    2031              :         int                             array_size;
    2032              :         int                             num_arrays = 0;
    2033              :         int                             parse_state[COLOPL_BC_MULTISORT_LAST]; /* 0 - flag not allowed 1 - flag allowed */
    2034              :         int                             sort_order = PHP_SORT_ASC;
    2035              :         int                             sort_type = PHP_SORT_REGULAR;
    2036              :         int                             i, k, n;
    2037              :         bucket_compare_func_t *func;
    2038              : 
    2039              :         ZEND_PARSE_PARAMETERS_START(1, -1)
    2040              :                 Z_PARAM_VARIADIC('+', args, argc)
    2041              :         ZEND_PARSE_PARAMETERS_END();
    2042              : 
    2043              :         /* Allocate space for storing pointers to input arrays and sort flags. */
    2044              :         arrays = (zval **)ecalloc(argc, sizeof(zval *));
    2045              :         for (i = 0; i < COLOPL_BC_MULTISORT_LAST; i++) {
    2046              :                 parse_state[i] = 0;
    2047              :         }
    2048              :         func = COLOPL_BC_G(multisort_func) = ecalloc(argc, sizeof(bucket_compare_func_t));
    2049              : 
    2050              :         /* Here we go through the input arguments and parse them. Each one can
    2051              :          * be either an array or a sort flag which follows an array. If not
    2052              :          * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
    2053              :          * accordingly. There can't be two sort flags of the same type after an
    2054              :          * array, and the very first argument has to be an array. */
    2055              :         for (i = 0; i < argc; i++) {
    2056              :                 zval *arg = &args[i];
    2057              : 
    2058              :                 ZVAL_DEREF(arg);
    2059              :                 if (Z_TYPE_P(arg) == IS_ARRAY) {
    2060              :                         SEPARATE_ARRAY(arg);
    2061              :                         /* We see the next array, so we update the sort flags of
    2062              :                          * the previous array and reset the sort flags. */
    2063              :                         if (i > 0) {
    2064              :                                 COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    2065              :                                 sort_order = PHP_SORT_ASC;
    2066              :                                 sort_type = PHP_SORT_REGULAR;
    2067              :                         }
    2068              :                         arrays[num_arrays++] = arg;
    2069              : 
    2070              :                         /* Next one may be an array or a list of sort flags. */
    2071              :                         for (k = 0; k < COLOPL_BC_MULTISORT_LAST; k++) {
    2072              :                                 parse_state[k] = 1;
    2073              :                         }
    2074              :                 } else if (Z_TYPE_P(arg) == IS_LONG) {
    2075              :                         switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
    2076              :                                 case PHP_SORT_ASC:
    2077              :                                 case PHP_SORT_DESC:
    2078              :                                         /* flag allowed here */
    2079              :                                         if (parse_state[COLOPL_BC_MULTISORT_ORDER] == 1) {
    2080              :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    2081              :                                                 sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? PHP_SORT_DESC : PHP_SORT_ASC;
    2082              :                                                 parse_state[COLOPL_BC_MULTISORT_ORDER] = 0;
    2083              :                                         } else {
    2084              :                                                 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
    2085              :                                                 COLOPL_BC_MULTISORT_ABORT;
    2086              :                                         }
    2087              :                                         break;
    2088              : 
    2089              :                                 case PHP_SORT_REGULAR:
    2090              :                                 case PHP_SORT_NUMERIC:
    2091              :                                 case PHP_SORT_STRING:
    2092              :                                 case PHP_SORT_NATURAL:
    2093              :                                 case PHP_SORT_LOCALE_STRING:
    2094              :                                         /* flag allowed here */
    2095              :                                         if (parse_state[COLOPL_BC_MULTISORT_TYPE] == 1) {
    2096              :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    2097              :                                                 sort_type = (int)Z_LVAL_P(arg);
    2098              :                                                 parse_state[COLOPL_BC_MULTISORT_TYPE] = 0;
    2099              :                                         } else {
    2100              :                                                 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
    2101              :                                                 COLOPL_BC_MULTISORT_ABORT;
    2102              :                                         }
    2103              :                                         break;
    2104              : 
    2105              :                                 default:
    2106              :                                         zend_argument_value_error(i + 1, "must be a valid sort flag");
    2107              :                                         COLOPL_BC_MULTISORT_ABORT;
    2108              :                                         break;
    2109              : 
    2110              :                         }
    2111              :                 } else {
    2112              :                         zend_argument_type_error(i + 1, "must be an array or a sort flag");
    2113              :                         COLOPL_BC_MULTISORT_ABORT;
    2114              :                 }
    2115              :         }
    2116              :         /* Take care of the last array sort flags. */
    2117              :         COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    2118              : 
    2119              :         /* Make sure the arrays are of the same size. */
    2120              :         array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
    2121              :         for (i = 0; i < num_arrays; i++) {
    2122              :                 if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != (uint32_t)array_size) {
    2123              :                         zend_value_error("Array sizes are inconsistent");
    2124              :                         COLOPL_BC_MULTISORT_ABORT;
    2125              :                 }
    2126              :         }
    2127              : 
    2128              :         /* If all arrays are empty we don't need to do anything. */
    2129              :         if (array_size < 1) {
    2130              :                 efree(func);
    2131              :                 efree(arrays);
    2132              :                 RETURN_TRUE;
    2133              :         }
    2134              : 
    2135              :         /* Create the indirection array. This array is of size MxN, where
    2136              :          * M is the number of entries in each input array and N is the number
    2137              :          * of the input arrays + 1. The last column is NULL to indicate the end
    2138              :          * of the row. */
    2139              :         indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
    2140              :         for (i = 0; i < array_size; i++) {
    2141              :                 indirect[i] = (Bucket *)safe_emalloc((num_arrays + 1), sizeof(Bucket), 0);
    2142              :         }
    2143              :         for (i = 0; i < num_arrays; i++) {
    2144              :                 k = 0;
    2145              :                 for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++) {
    2146              :                         p = Z_ARRVAL_P(arrays[i])->arData + idx;
    2147              :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2148              :                         indirect[k][i] = *p;
    2149              :                         k++;
    2150              :                 }
    2151              :         }
    2152              :         for (k = 0; k < array_size; k++) {
    2153              :                 ZVAL_UNDEF(&indirect[k][num_arrays].val);
    2154              :         }
    2155              : 
    2156              :         /* Do the actual sort magic - bada-bim, bada-boom. */
    2157              :         zend_sort(indirect, array_size, sizeof(Bucket *), php_colopl_bc_multisort_compare, (swap_func_t)colopl_bc_array_bucket_p_swap);
    2158              : 
    2159              :         /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
    2160              :         for (i = 0; i < num_arrays; i++) {
    2161              :                 int repack;
    2162              : 
    2163              :                 hash = Z_ARRVAL_P(arrays[i]);
    2164              :                 hash->nNumUsed = array_size;
    2165              :                 hash->nInternalPointer = 0;
    2166              :                 repack = !(HT_FLAGS(hash) & HASH_FLAG_PACKED);
    2167              : 
    2168              :                 for (n = 0, k = 0; k < array_size; k++) {
    2169              :                         hash->arData[k] = indirect[k][i];
    2170              :                         if (hash->arData[k].key == NULL) {
    2171              :                                 hash->arData[k].h = n++;
    2172              :                         } else {
    2173              :                                 repack = 0;
    2174              :                         }
    2175              :                 }
    2176              :                 hash->nNextFreeElement = array_size;
    2177              :                 if (repack) {
    2178              :                         zend_hash_to_packed(hash);
    2179              :                 } else if (!(HT_FLAGS(hash) & HASH_FLAG_PACKED)) {
    2180              :                         zend_hash_rehash(hash);
    2181              :                 }
    2182              :         }
    2183              : 
    2184              :         /* Clean up. */
    2185              :         for (i = 0; i < array_size; i++) {
    2186              :                 efree(indirect[i]);
    2187              :         }
    2188              :         efree(indirect);
    2189              :         efree(func);
    2190              :         efree(arrays);
    2191              :         RETURN_TRUE;
    2192              : }
    2193              : #else
    2194            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_multisort)
    2195              : {
    2196              :         zval*                   args;
    2197              :         zval**                  arrays;
    2198              :         Bucket**                indirect;
    2199              :         uint32_t                idx;
    2200              :         HashTable*              hash;
    2201              :         int                             argc;
    2202              :         int                             array_size;
    2203            4 :         int                             num_arrays = 0;
    2204              :         int                             parse_state[COLOPL_BC_MULTISORT_LAST];   /* 0 - flag not allowed 1 - flag allowed */
    2205            4 :         int                             sort_order = PHP_SORT_ASC;
    2206            4 :         int                             sort_type  = PHP_SORT_REGULAR;
    2207              :         int                             i, k, n;
    2208              :         bucket_compare_func_t *func;
    2209              : 
    2210            4 :         ZEND_PARSE_PARAMETERS_START(1, -1)
    2211            4 :                 Z_PARAM_VARIADIC('+', args, argc)
    2212            4 :         ZEND_PARSE_PARAMETERS_END();
    2213              : 
    2214              :         /* Allocate space for storing pointers to input arrays and sort flags. */
    2215            4 :         arrays = (zval **)ecalloc(argc, sizeof(zval *));
    2216           12 :         for (i = 0; i < COLOPL_BC_MULTISORT_LAST; i++) {
    2217            8 :                 parse_state[i] = 0;
    2218              :         }
    2219            4 :         func = COLOPL_BC_G(multisort_func) = ecalloc(argc, sizeof(bucket_compare_func_t));
    2220              : 
    2221              :         /* Here we go through the input arguments and parse them. Each one can
    2222              :          * be either an array or a sort flag which follows an array. If not
    2223              :          * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
    2224              :          * accordingly. There can't be two sort flags of the same type after an
    2225              :          * array, and the very first argument has to be an array. */
    2226           12 :         for (i = 0; i < argc; i++) {
    2227            8 :                 zval *arg = &args[i];
    2228              : 
    2229            8 :                 ZVAL_DEREF(arg);
    2230            8 :                 if (Z_TYPE_P(arg) == IS_ARRAY) {
    2231            8 :                         SEPARATE_ARRAY(arg);
    2232              :                         /* We see the next array, so we update the sort flags of
    2233              :                          * the previous array and reset the sort flags. */
    2234            8 :                         if (i > 0) {
    2235            4 :                                 COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    2236            4 :                                 sort_order = PHP_SORT_ASC;
    2237            4 :                                 sort_type = PHP_SORT_REGULAR;
    2238              :                         }
    2239            8 :                         arrays[num_arrays++] = arg;
    2240              : 
    2241              :                         /* Next one may be an array or a list of sort flags. */
    2242           24 :                         for (k = 0; k < COLOPL_BC_MULTISORT_LAST; k++) {
    2243           16 :                                 parse_state[k] = 1;
    2244              :                         }
    2245            0 :                 } else if (Z_TYPE_P(arg) == IS_LONG) {
    2246            0 :                         switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
    2247            0 :                                 case PHP_SORT_ASC:
    2248              :                                 case PHP_SORT_DESC:
    2249              :                                         /* flag allowed here */
    2250            0 :                                         if (parse_state[COLOPL_BC_MULTISORT_ORDER] == 1) {
    2251              :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    2252            0 :                                                 sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? PHP_SORT_DESC : PHP_SORT_ASC;
    2253            0 :                                                 parse_state[COLOPL_BC_MULTISORT_ORDER] = 0;
    2254              :                                         } else {
    2255            0 :                                                 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
    2256            0 :                                                 COLOPL_BC_MULTISORT_ABORT;
    2257              :                                         }
    2258            0 :                                         break;
    2259              : 
    2260            0 :                                 case PHP_SORT_REGULAR:
    2261              :                                 case PHP_SORT_NUMERIC:
    2262              :                                 case PHP_SORT_STRING:
    2263              :                                 case PHP_SORT_NATURAL:
    2264              :                                 case PHP_SORT_LOCALE_STRING:
    2265              :                                         /* flag allowed here */
    2266            0 :                                         if (parse_state[COLOPL_BC_MULTISORT_TYPE] == 1) {
    2267              :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    2268            0 :                                                 sort_type = (int)Z_LVAL_P(arg);
    2269            0 :                                                 parse_state[COLOPL_BC_MULTISORT_TYPE] = 0;
    2270              :                                         } else {
    2271            0 :                                                 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
    2272            0 :                                                 COLOPL_BC_MULTISORT_ABORT;
    2273              :                                         }
    2274            0 :                                         break;
    2275              : 
    2276            0 :                                 default:
    2277            0 :                                         zend_argument_value_error(i + 1, "must be a valid sort flag");
    2278            0 :                                         COLOPL_BC_MULTISORT_ABORT;
    2279              :                                         break;
    2280              : 
    2281              :                         }
    2282              :                 } else {
    2283            0 :                         zend_argument_type_error(i + 1, "must be an array or a sort flag");
    2284            0 :                         COLOPL_BC_MULTISORT_ABORT;
    2285              :                 }
    2286              :         }
    2287              :         /* Take care of the last array sort flags. */
    2288            4 :         COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    2289              : 
    2290              :         /* Make sure the arrays are of the same size. */
    2291            4 :         array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
    2292           12 :         for (i = 0; i < num_arrays; i++) {
    2293            8 :                 if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != (uint32_t)array_size) {
    2294            0 :                         zend_value_error("Array sizes are inconsistent");
    2295            0 :                         COLOPL_BC_MULTISORT_ABORT;
    2296              :                 }
    2297              :         }
    2298              : 
    2299              :         /* If all arrays are empty we don't need to do anything. */
    2300            4 :         if (array_size < 1) {
    2301            0 :                 efree(func);
    2302            0 :                 efree(arrays);
    2303            0 :                 RETURN_TRUE;
    2304              :         }
    2305              : 
    2306              :         /* Create the indirection array. This array is of size MxN, where
    2307              :          * M is the number of entries in each input array and N is the number
    2308              :          * of the input arrays + 1. The last column is UNDEF to indicate the end
    2309              :          * of the row. It also stores the original position for stable sorting. */
    2310            4 :         indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
    2311          404 :         for (i = 0; i < array_size; i++) {
    2312          400 :                 indirect[i] = (Bucket *)safe_emalloc((num_arrays + 1), sizeof(Bucket), 0);
    2313              :         }
    2314           12 :         for (i = 0; i < num_arrays; i++) {
    2315            8 :                 k = 0;
    2316            8 :                 if (HT_IS_PACKED(Z_ARRVAL_P(arrays[i]))) {
    2317            8 :                         zval *zv = Z_ARRVAL_P(arrays[i])->arPacked;
    2318          808 :                         for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++, zv++) {
    2319          800 :                                 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
    2320          800 :                                 ZVAL_COPY_VALUE(&indirect[k][i].val, zv);
    2321          800 :                                 indirect[k][i].h = idx;
    2322          800 :                                 indirect[k][i].key = NULL;
    2323          800 :                                 k++;
    2324              :                         }
    2325              :                 } else {
    2326            0 :                         Bucket *p = Z_ARRVAL_P(arrays[i])->arData;
    2327            0 :                         for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++, p++) {
    2328            0 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2329            0 :                                 indirect[k][i] = *p;
    2330            0 :                                 k++;
    2331              :                         }
    2332              :                 }
    2333              :         }
    2334          404 :         for (k = 0; k < array_size; k++) {
    2335          400 :                 ZVAL_UNDEF(&indirect[k][num_arrays].val);
    2336          400 :                 Z_EXTRA_P(&indirect[k][num_arrays].val) = k;
    2337              :         }
    2338              : 
    2339              :         /* Do the actual sort magic - bada-bim, bada-boom. */
    2340            4 :         zend_sort(indirect, array_size, sizeof(Bucket *), php_colopl_bc_multisort_compare, (swap_func_t)colopl_bc_array_bucket_p_swap);
    2341              : 
    2342              :         /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
    2343           12 :         for (i = 0; i < num_arrays; i++) {
    2344            8 :                 hash = Z_ARRVAL_P(arrays[i]);
    2345            8 :                 hash->nNumUsed = array_size;
    2346            8 :                 hash->nNextFreeElement = array_size;
    2347            8 :                 hash->nInternalPointer = 0;
    2348            8 :                 if (HT_IS_PACKED(hash)) {
    2349          808 :                         for (k = 0; k < array_size; k++) {
    2350          800 :                                 ZVAL_COPY_VALUE(&hash->arPacked[k], &indirect[k][i].val);
    2351              :                         }
    2352              :                 } else {
    2353            0 :                         int repack = 1;
    2354              : 
    2355            0 :                         for (n = 0, k = 0; k < array_size; k++) {
    2356            0 :                                 hash->arData[k] = indirect[k][i];
    2357            0 :                                 if (hash->arData[k].key == NULL) {
    2358            0 :                                         hash->arData[k].h = n++;
    2359              :                                 } else {
    2360            0 :                                         repack = 0;
    2361              :                                 }
    2362              :                         }
    2363            0 :                         if (repack) {
    2364            0 :                                 zend_hash_to_packed(hash);
    2365              :                         }
    2366              :                 }
    2367              :         }
    2368              : 
    2369              :         /* Clean up. */
    2370          404 :         for (i = 0; i < array_size; i++) {
    2371          400 :                 efree(indirect[i]);
    2372              :         }
    2373            4 :         efree(indirect);
    2374            4 :         efree(func);
    2375            4 :         efree(arrays);
    2376            4 :         RETURN_TRUE;
    2377              : }
    2378              : #endif
    2379              : 
    2380              : /* BinaryOps */
    2381              : 
    2382         1184 : PHP_FUNCTION(Colopl_ColoplBc_Php74_eq)
    2383              : {
    2384              :         zval *op1, *op2;
    2385              : 
    2386         1184 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2387         1184 :                 Z_PARAM_ZVAL(op1)
    2388         1184 :                 Z_PARAM_ZVAL(op2)
    2389         1184 :         ZEND_PARSE_PARAMETERS_END();
    2390              : 
    2391         1184 :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) == 0);
    2392              : }
    2393              : 
    2394            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_neq)
    2395              : {
    2396              :         zval *op1, *op2;
    2397              : 
    2398            4 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2399            4 :                 Z_PARAM_ZVAL(op1)
    2400            4 :                 Z_PARAM_ZVAL(op2)
    2401            4 :         ZEND_PARSE_PARAMETERS_END();
    2402              : 
    2403            4 :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) != 0);
    2404              : }
    2405              : 
    2406         1160 : PHP_FUNCTION(Colopl_ColoplBc_Php74_lt)
    2407              : {
    2408              :         zval *op1, *op2;
    2409              : 
    2410         1160 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2411         1160 :                 Z_PARAM_ZVAL(op1)
    2412         1160 :                 Z_PARAM_ZVAL(op2)
    2413         1160 :         ZEND_PARSE_PARAMETERS_END();
    2414              : 
    2415         1160 :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) < 0);
    2416              : }
    2417              : 
    2418         1160 : PHP_FUNCTION(Colopl_ColoplBc_Php74_lte)
    2419              : {
    2420              :         zval *op1, *op2;
    2421              : 
    2422         1160 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2423         1160 :                 Z_PARAM_ZVAL(op1)
    2424         1160 :                 Z_PARAM_ZVAL(op2)
    2425         1160 :         ZEND_PARSE_PARAMETERS_END();
    2426              : 
    2427         1160 :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) <= 0);
    2428              : }
    2429              : 
    2430         1160 : PHP_FUNCTION(Colopl_ColoplBc_Php74_gt)
    2431              : {
    2432              :         zval *op1, *op2;
    2433              : 
    2434         1160 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2435         1160 :                 Z_PARAM_ZVAL(op1)
    2436         1160 :                 Z_PARAM_ZVAL(op2)
    2437         1160 :         ZEND_PARSE_PARAMETERS_END();
    2438              : 
    2439         1160 :         RETURN_BOOL(php_colopl_bc_compare(op2, op1) < 0);
    2440              : }
    2441              : 
    2442         1160 : PHP_FUNCTION(Colopl_ColoplBc_Php74_gte)
    2443              : {
    2444              :         zval *op1, *op2;
    2445              : 
    2446         1160 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2447         1160 :                 Z_PARAM_ZVAL(op1)
    2448         1160 :                 Z_PARAM_ZVAL(op2)
    2449         1160 :         ZEND_PARSE_PARAMETERS_END();
    2450              : 
    2451         1160 :         RETURN_BOOL(php_colopl_bc_compare(op2, op1) <= 0);
    2452              : }
    2453              : 
    2454            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_spaceship)
    2455              : {
    2456              :         zval *op1, *op2;
    2457              : 
    2458            4 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2459            4 :                 Z_PARAM_ZVAL(op1)
    2460            4 :                 Z_PARAM_ZVAL(op2)
    2461            4 :         ZEND_PARSE_PARAMETERS_END();
    2462              : 
    2463            4 :         RETURN_LONG(php_colopl_bc_compare(op1, op2));
    2464              : }
        

Generated by: LCOV version 2.0-1