@@ -110,94 +110,20 @@ static zend_never_inline ZEND_COLD int stable_sort_fallback(Bucket *a, Bucket *b
110110static int php_array_compare_transitive (zval * op1 , zval * op2 );
111111
112112/* Generate inlined unstable and stable variants, and non-inlined reversed variants. */
113- #define DEFINE_SORT_VARIANTS_USING (name , impl ) \
113+ #define DEFINE_SORT_VARIANTS (name ) \
114114 static zend_never_inline int php_array_##name##_unstable(Bucket *a, Bucket *b) { \
115- return (impl) (a, b); \
115+ return php_array_##name##_unstable_i (a, b); \
116116 } \
117117 static zend_never_inline int php_array_##name(Bucket *a, Bucket *b) { \
118- RETURN_STABLE_SORT(a, b, (impl) (a, b)); \
118+ RETURN_STABLE_SORT(a, b, php_array_##name##_unstable_i (a, b)); \
119119 } \
120120 static zend_never_inline int php_array_reverse_##name##_unstable(Bucket *a, Bucket *b) { \
121121 return php_array_##name##_unstable(a, b) * -1; \
122122 } \
123123 static zend_never_inline int php_array_reverse_##name(Bucket *a, Bucket *b) { \
124124 RETURN_STABLE_SORT(a, b, php_array_reverse_##name##_unstable(a, b)); \
125- } \
126-
127- #define DEFINE_SORT_VARIANTS (name ) \
128- DEFINE_SORT_VARIANTS_USING(name, php_array_##name##_unstable_i)
129-
130- static zend_always_inline bool php_array_is_enum_zval (zval * zv )
131- {
132- return Z_TYPE_P (zv ) == IS_OBJECT && (Z_OBJCE_P (zv )-> ce_flags & ZEND_ACC_ENUM );
133- }
134-
135- static zend_always_inline int php_array_compare_enum_zvals (zval * lhs , zval * rhs )
136- {
137- const bool lhs_enum = php_array_is_enum_zval (lhs );
138- const bool rhs_enum = php_array_is_enum_zval (rhs );
139-
140- if (lhs_enum && rhs_enum ) {
141- zend_object * lhs_obj = Z_OBJ_P (lhs );
142- zend_object * rhs_obj = Z_OBJ_P (rhs );
143-
144- if (lhs_obj == rhs_obj ) {
145- return 0 ;
146- }
147-
148- if (lhs_obj -> ce != rhs_obj -> ce ) {
149- return zend_compare_non_numeric_strings (lhs_obj -> ce -> name , rhs_obj -> ce -> name );
150- }
151-
152- if (lhs_obj -> ce -> enum_backing_type != IS_UNDEF ) {
153- zval * lhs_value = zend_enum_fetch_case_value (lhs_obj );
154- zval * rhs_value = zend_enum_fetch_case_value (rhs_obj );
155-
156- if (lhs_obj -> ce -> enum_backing_type == IS_LONG ) {
157- zend_long lhs_long = Z_LVAL_P (lhs_value );
158- zend_long rhs_long = Z_LVAL_P (rhs_value );
159- if (lhs_long != rhs_long ) {
160- return lhs_long < rhs_long ? -1 : 1 ;
161- }
162- } else {
163- ZEND_ASSERT (lhs_obj -> ce -> enum_backing_type == IS_STRING );
164- zend_string * lhs_str = Z_STR_P (lhs_value );
165- zend_string * rhs_str = Z_STR_P (rhs_value );
166- if (lhs_str != rhs_str ) {
167- zend_ulong lhs_hash = ZSTR_HASH (lhs_str );
168- zend_ulong rhs_hash = ZSTR_HASH (rhs_str );
169- if (lhs_hash != rhs_hash ) {
170- return lhs_hash < rhs_hash ? -1 : 1 ;
171- }
172- int cmp = zend_compare_non_numeric_strings (lhs_str , rhs_str );
173- if (cmp != 0 ) {
174- return cmp ;
175- }
176- }
177- }
178- }
179-
180- zend_string * lhs_case = Z_STR_P (zend_enum_fetch_case_name (lhs_obj ));
181- zend_string * rhs_case = Z_STR_P (zend_enum_fetch_case_name (rhs_obj ));
182- if (lhs_case != rhs_case ) {
183- zend_ulong lhs_hash = ZSTR_HASH (lhs_case );
184- zend_ulong rhs_hash = ZSTR_HASH (rhs_case );
185- if (lhs_hash != rhs_hash ) {
186- return lhs_hash < rhs_hash ? -1 : 1 ;
187- }
188- int cmp = zend_compare_non_numeric_strings (lhs_case , rhs_case );
189- if (cmp != 0 ) {
190- return cmp ;
191- }
192- }
193-
194- /* Should not happen for userland enums, but keep ordering deterministic for transitivity. */
195- return lhs_obj -> handle < rhs_obj -> handle ? -1 : 1 ;
196125 }
197126
198- return lhs_enum ? 1 : -1 ;
199- }
200-
201127static zend_always_inline int php_array_key_compare_numeric_unstable_i (Bucket * f , Bucket * s ) /* {{{ */
202128{
203129 if (f -> key == NULL && s -> key == NULL ) {
@@ -399,6 +325,77 @@ DEFINE_SORT_VARIANTS(data_compare_string_locale);
399325DEFINE_SORT_VARIANTS (natural_compare );
400326DEFINE_SORT_VARIANTS (natural_case_compare );
401327
328+ static zend_always_inline bool php_array_is_enum_zval (zval * zv )
329+ {
330+ return Z_TYPE_P (zv ) == IS_OBJECT && (Z_OBJCE_P (zv )-> ce_flags & ZEND_ACC_ENUM );
331+ }
332+
333+ static zend_always_inline int php_array_compare_enum_zvals (zval * lhs , zval * rhs )
334+ {
335+ const bool lhs_enum = php_array_is_enum_zval (lhs );
336+ const bool rhs_enum = php_array_is_enum_zval (rhs );
337+
338+ if (lhs_enum && rhs_enum ) {
339+ zend_object * lhs_obj = Z_OBJ_P (lhs );
340+ zend_object * rhs_obj = Z_OBJ_P (rhs );
341+
342+ if (lhs_obj == rhs_obj ) {
343+ return 0 ;
344+ }
345+
346+ if (lhs_obj -> ce != rhs_obj -> ce ) {
347+ return zend_compare_non_numeric_strings (lhs_obj -> ce -> name , rhs_obj -> ce -> name );
348+ }
349+
350+ if (lhs_obj -> ce -> enum_backing_type != IS_UNDEF ) {
351+ zval * lhs_value = zend_enum_fetch_case_value (lhs_obj );
352+ zval * rhs_value = zend_enum_fetch_case_value (rhs_obj );
353+
354+ if (lhs_obj -> ce -> enum_backing_type == IS_LONG ) {
355+ zend_long lhs_long = Z_LVAL_P (lhs_value );
356+ zend_long rhs_long = Z_LVAL_P (rhs_value );
357+ if (lhs_long != rhs_long ) {
358+ return lhs_long < rhs_long ? -1 : 1 ;
359+ }
360+ } else {
361+ ZEND_ASSERT (lhs_obj -> ce -> enum_backing_type == IS_STRING );
362+ zend_string * lhs_str = Z_STR_P (lhs_value );
363+ zend_string * rhs_str = Z_STR_P (rhs_value );
364+ if (lhs_str != rhs_str ) {
365+ zend_ulong lhs_hash = ZSTR_HASH (lhs_str );
366+ zend_ulong rhs_hash = ZSTR_HASH (rhs_str );
367+ if (lhs_hash != rhs_hash ) {
368+ return lhs_hash < rhs_hash ? -1 : 1 ;
369+ }
370+ int cmp = zend_compare_non_numeric_strings (lhs_str , rhs_str );
371+ if (cmp != 0 ) {
372+ return cmp ;
373+ }
374+ }
375+ }
376+ }
377+
378+ zend_string * lhs_case = Z_STR_P (zend_enum_fetch_case_name (lhs_obj ));
379+ zend_string * rhs_case = Z_STR_P (zend_enum_fetch_case_name (rhs_obj ));
380+ if (lhs_case != rhs_case ) {
381+ zend_ulong lhs_hash = ZSTR_HASH (lhs_case );
382+ zend_ulong rhs_hash = ZSTR_HASH (rhs_case );
383+ if (lhs_hash != rhs_hash ) {
384+ return lhs_hash < rhs_hash ? -1 : 1 ;
385+ }
386+ int cmp = zend_compare_non_numeric_strings (lhs_case , rhs_case );
387+ if (cmp != 0 ) {
388+ return cmp ;
389+ }
390+ }
391+
392+ /* Should not happen for userland enums, but keep ordering deterministic for transitivity. */
393+ return lhs_obj -> handle < rhs_obj -> handle ? -1 : 1 ;
394+ }
395+
396+ return lhs_enum ? 1 : -1 ;
397+ }
398+
402399static int php_array_hash_compare_transitive (zval * zv1 , zval * zv2 ) /* {{{ */
403400{
404401 return php_array_compare_transitive (zv1 , zv2 );
0 commit comments