[php-src] master: ext/intl: Pre-size arrays created from ICU enumerations (#22483)

Xuyang Zhang via GitHub <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Xuyang Zhang (kn1g78)
Committer: GitHub (web-flow)
Pusher: LamentXU123
Date: 2026-06-27T18:08:38+08:00

Commit: https://github.com/php/php-src/commit/824770675130360543604e03b9f828a0e41c91ad
Raw diff: https://github.com/php/php-src/commit/824770675130360543604e03b9f828a0e41c91ad.diff

ext/intl: Pre-size arrays created from ICU enumerations (#22483)

Use uenum_count() to pre-size arrays built from ICU enumerations.

This avoids unnecessary HashTable growth in transliterator_list_ids(),
resourcebundle_locales() and locale_get_keywords().

locale_get_keywords() also uses the keyword length reported by ICU when
inserting the associative entry, with a fallback to strlen() for unknown
lengths.

If counting fails, the previous behavior is preserved by falling back to an
unsized array initialization.

Changed paths:
  M  UPGRADING
  M  ext/intl/resourcebundle/resourcebundle_class.cpp
  M  ext/intl/transliterator/transliterator_methods.cpp


Diff:

diff --git a/UPGRADING b/UPGRADING
index 15c1aad15db0..0c5253267e39 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -500,6 +500,10 @@ PHP 8.6 UPGRADE NOTES
   . Improved performance of indentation generation in json_encode()
     when using PHP_JSON_PRETTY_PRINT.
 
+- Intl:
+  . Improved performance of transliterator_list_ids() and
+    resourcebundle_locales() by pre-allocating their returned arrays.
+
 - Phar:
   . Reduced temporary allocations when iterating Phar directories.
 
diff --git a/ext/intl/resourcebundle/resourcebundle_class.cpp b/ext/intl/resourcebundle/resourcebundle_class.cpp
index f796a6ffc8aa..7e22e9e8c7df 100644
--- a/ext/intl/resourcebundle/resourcebundle_class.cpp
+++ b/ext/intl/resourcebundle/resourcebundle_class.cpp
@@ -339,6 +339,7 @@ U_CFUNC PHP_FUNCTION( resourcebundle_locales )
 	size_t    bundlename_len = 0;
 	const char * entry;
 	int entry_len;
+	int32_t count;
 	UEnumeration *icuenum;
 	UErrorCode   icuerror = U_ZERO_ERROR;
 
@@ -364,7 +365,13 @@ U_CFUNC PHP_FUNCTION( resourcebundle_locales )
 	uenum_reset( icuenum, &icuerror );
 	INTL_CHECK_STATUS(icuerror, "Cannot iterate locales list");
 
-	array_init( return_value );
+	count = uenum_count( icuenum, &icuerror );
+	if (U_FAILURE(icuerror)) {
+		count = 0;
+		icuerror = U_ZERO_ERROR;
+	}
+
+	array_init_size( return_value, count );
 	while ((entry = uenum_next( icuenum, &entry_len, &icuerror ))) {
 		add_next_index_stringl( return_value, (char *) entry, entry_len);
 	}
diff --git a/ext/intl/transliterator/transliterator_methods.cpp b/ext/intl/transliterator/transliterator_methods.cpp
index 45dd00b42bcf..8efcff95b310 100644
--- a/ext/intl/transliterator/transliterator_methods.cpp
+++ b/ext/intl/transliterator/transliterator_methods.cpp
@@ -21,6 +21,8 @@
 #include <unicode/unistr.h>
 #endif
 
+#include <unicode/uenum.h>
+
 extern "C" {
 #include "php_intl.h"
 #include "intl_data.h"
@@ -226,6 +228,7 @@ U_CFUNC PHP_FUNCTION( transliterator_list_ids )
 	UEnumeration  *en;
 	const UChar	  *elem;
 	int32_t		  elem_len;
+	int32_t		  count;
 	UErrorCode	  status = U_ZERO_ERROR;
 
 	intl_error_reset( nullptr );
@@ -236,7 +239,14 @@ U_CFUNC PHP_FUNCTION( transliterator_list_ids )
 	INTL_CHECK_STATUS( status,
 		"Failed to obtain registered transliterators" );
 
-	array_init( return_value );
+	count = uenum_count( en, &status );
+	if( U_FAILURE( status ) )
+	{
+		count = 0;
+		status = U_ZERO_ERROR;
+	}
+
+	array_init_size( return_value, count );
 	while( (elem = uenum_unext( en, &elem_len, &status )) )
 	{
 		zend_string *el = intl_convert_utf16_to_utf8(elem, elem_len, &status );
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.