Commit ae62043aa34 for php.net

commit ae62043aa340871abfeea8568565d23d8b42f35a
Author: Weilin Du <weilindu@php.net>
Date:   Sun Sep 13 00:04:17 2026 +0800

    ext/mbstring: Optimize mb_str_pad() using doubling copies (#23667)

    Follow-up #23661. Use the same optimization on mb_str_pad.

    Co-authored-by: David CARLIER <devnexen@gmail.com>

diff --git a/UPGRADING b/UPGRADING
index 3980faa4294..7c7b727759b 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -1091,6 +1091,9 @@ PHP 8.6 UPGRADE NOTES
   . Improved performance of transliterator_list_ids() and
     resourcebundle_locales() by pre-allocating their returned arrays.

+- Mbstring:
+  . Improved performance of mb_str_pad().
+
 - Phar:
   . Reduced temporary allocations when iterating Phar directories.

diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c
index ed3e8bd1cf4..c701a23183b 100644
--- a/ext/mbstring/mbstring.c
+++ b/ext/mbstring/mbstring.c
@@ -5906,6 +5906,28 @@ PHP_FUNCTION(mb_chr)
 }
 /* }}} */

+static char *php_mb_str_pad_fill(char *buffer, const zend_string *pad, size_t pad_bytes)
+{
+	if (pad_bytes == 0) {
+		return buffer;
+	}
+	if (ZSTR_LEN(pad) == 1) {
+		memset(buffer, ZSTR_VAL(pad)[0], pad_bytes);
+		return buffer + pad_bytes;
+	}
+
+	const char *start = buffer;
+	const char *end = buffer + pad_bytes;
+	buffer = zend_mempcpy(buffer, ZSTR_VAL(pad), ZSTR_LEN(pad));
+
+	/* Double the filled area on each iteration. */
+	while (buffer < end) {
+		size_t len = MIN(buffer - start, end - buffer);
+		buffer = zend_mempcpy(buffer, start, len);
+	}
+	return buffer;
+}
+
 PHP_FUNCTION(mb_str_pad)
 {
 	zend_string *input, *encoding_str = NULL, *pad = ZSTR_CHAR(' ');
@@ -6006,9 +6028,7 @@ PHP_FUNCTION(mb_str_pad)
 	char *buffer = ZSTR_VAL(result);

 	/* First we pad the left. */
-	for (size_t i = 0; i < full_left_pad_copies; i++, buffer += ZSTR_LEN(pad)) {
-		memcpy(buffer, ZSTR_VAL(pad), ZSTR_LEN(pad));
-	}
+	buffer = php_mb_str_pad_fill(buffer, pad, full_left_pad_bytes);
 	memcpy(buffer, ZSTR_VAL(remaining_left_pad_str), ZSTR_LEN(remaining_left_pad_str));
 	buffer += ZSTR_LEN(remaining_left_pad_str);

@@ -6017,9 +6037,7 @@ PHP_FUNCTION(mb_str_pad)
 	buffer += ZSTR_LEN(input);

 	/* Finally, we pad on the right. */
-	for (size_t i = 0; i < full_right_pad_copies; i++, buffer += ZSTR_LEN(pad)) {
-		memcpy(buffer, ZSTR_VAL(pad), ZSTR_LEN(pad));
-	}
+	buffer = php_mb_str_pad_fill(buffer, pad, full_right_pad_bytes);
 	memcpy(buffer, ZSTR_VAL(remaining_right_pad_str), ZSTR_LEN(remaining_right_pad_str));

 	ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';