@@ -2477,6 +2477,122 @@ ZEND_API int ZEND_FASTCALL _zend_handle_numeric_str_ex(const char *key, size_t l
2477
2477
}
2478
2478
}
2479
2479
2480
+ /* Takes a "symtable" hashtable (contains integer and non-numeric string keys)
2481
+ * and converts it to a "proptable" (contains only string keys).
2482
+ * If the symtable didn't need duplicating, its refcount is incremented.
2483
+ */
2484
+ ZEND_API HashTable * ZEND_FASTCALL zend_symtable_to_proptable (HashTable * ht )
2485
+ {
2486
+ zend_ulong num_key ;
2487
+ zend_string * str_key ;
2488
+ zval * zv ;
2489
+
2490
+ if (UNEXPECTED (HT_IS_PACKED (ht ))) {
2491
+ goto convert ;
2492
+ }
2493
+
2494
+ ZEND_HASH_FOREACH_KEY_VAL (ht , num_key , str_key , zv ) {
2495
+ if (!str_key ) {
2496
+ goto convert ;
2497
+ }
2498
+ } ZEND_HASH_FOREACH_END ();
2499
+
2500
+ if (!(GC_FLAGS (ht ) & IS_ARRAY_IMMUTABLE )) {
2501
+ GC_REFCOUNT (ht )++ ;
2502
+ }
2503
+
2504
+ return ht ;
2505
+
2506
+ convert :
2507
+ {
2508
+ HashTable * new_ht = emalloc (sizeof (HashTable ));
2509
+
2510
+ zend_hash_init (new_ht , zend_hash_num_elements (ht ), NULL , ZVAL_PTR_DTOR , 0 );
2511
+
2512
+ ZEND_HASH_FOREACH_KEY_VAL (ht , num_key , str_key , zv ) {
2513
+ if (!str_key ) {
2514
+ str_key = zend_long_to_str (num_key );
2515
+ zend_string_delref (str_key );
2516
+ }
2517
+ do {
2518
+ if (Z_OPT_REFCOUNTED_P (zv )) {
2519
+ if (Z_ISREF_P (zv ) && Z_REFCOUNT_P (zv ) == 1 ) {
2520
+ zv = Z_REFVAL_P (zv );
2521
+ if (!Z_OPT_REFCOUNTED_P (zv )) {
2522
+ break ;
2523
+ }
2524
+ }
2525
+ Z_ADDREF_P (zv );
2526
+ }
2527
+ } while (0 );
2528
+ zend_hash_update (new_ht , str_key , zv );
2529
+ } ZEND_HASH_FOREACH_END ();
2530
+
2531
+ return new_ht ;
2532
+ }
2533
+ }
2534
+
2535
+ /* Takes a "proptable" hashtable (contains only string keys) and converts it to
2536
+ * a "symtable" (contains integer and non-numeric string keys).
2537
+ * If the proptable didn't need duplicating, its refcount is incremented.
2538
+ */
2539
+ ZEND_API HashTable * ZEND_FASTCALL zend_proptable_to_symtable (HashTable * ht , zend_bool always_duplicate )
2540
+ {
2541
+ zend_ulong num_key ;
2542
+ zend_string * str_key ;
2543
+ zval * zv ;
2544
+
2545
+ ZEND_HASH_FOREACH_KEY_VAL (ht , num_key , str_key , zv ) {
2546
+ /* The `str_key &&` here might seem redundant: property tables should
2547
+ * only have string keys. Unfortunately, this isn't true, at the very
2548
+ * least because of ArrayObject, which stores a symtable where the
2549
+ * property table should be.
2550
+ */
2551
+ if (str_key && ZEND_HANDLE_NUMERIC (str_key , num_key )) {
2552
+ goto convert ;
2553
+ }
2554
+ } ZEND_HASH_FOREACH_END ();
2555
+
2556
+ if (always_duplicate ) {
2557
+ return zend_array_dup (ht );
2558
+ }
2559
+
2560
+ if (EXPECTED (!(GC_FLAGS (ht ) & IS_ARRAY_IMMUTABLE ))) {
2561
+ GC_REFCOUNT (ht )++ ;
2562
+ }
2563
+
2564
+ return ht ;
2565
+
2566
+ convert :
2567
+ {
2568
+ HashTable * new_ht = emalloc (sizeof (HashTable ));
2569
+
2570
+ zend_hash_init (new_ht , zend_hash_num_elements (ht ), NULL , ZVAL_PTR_DTOR , 0 );
2571
+
2572
+ ZEND_HASH_FOREACH_KEY_VAL (ht , num_key , str_key , zv ) {
2573
+ do {
2574
+ if (Z_OPT_REFCOUNTED_P (zv )) {
2575
+ if (Z_ISREF_P (zv ) && Z_REFCOUNT_P (zv ) == 1 ) {
2576
+ zv = Z_REFVAL_P (zv );
2577
+ if (!Z_OPT_REFCOUNTED_P (zv )) {
2578
+ break ;
2579
+ }
2580
+ }
2581
+ Z_ADDREF_P (zv );
2582
+ }
2583
+ } while (0 );
2584
+ /* Again, thank ArrayObject for `!str_key ||`. */
2585
+ if (!str_key || ZEND_HANDLE_NUMERIC (str_key , num_key )) {
2586
+ zend_hash_index_update (new_ht , num_key , zv );
2587
+ } else {
2588
+ zend_hash_update (new_ht , str_key , zv );
2589
+ }
2590
+ } ZEND_HASH_FOREACH_END ();
2591
+
2592
+ return new_ht ;
2593
+ }
2594
+ }
2595
+
2480
2596
/*
2481
2597
* Local variables:
2482
2598
* tab-width: 4
0 commit comments