This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
utf8_to_bytes(): Avoid work if possible
authorKarl Williamson <khw@cpan.org>
Tue, 6 Jun 2017 01:21:41 +0000 (19:21 -0600)
committerKarl Williamson <khw@cpan.org>
Thu, 8 Jun 2017 17:04:43 +0000 (11:04 -0600)
This converts to use the new function is_utf8_invariant_string_loc() to
find the first variant in the input.  If none are found, the function is
a no-op.  If the intial part of the input is all invariants, they are
now skipped during conversion, resulting in less work for such input.

The new function could also be optimized to speed up searching.

utf8.c

diff --git a/utf8.c b/utf8.c
index e13d5e9..738bb6b 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -1920,14 +1920,24 @@ If you need a copy of the string, see L</bytes_from_utf8>.
 U8 *
 Perl_utf8_to_bytes(pTHX_ U8 *s, STRLEN *len)
 {
-    U8 * const save = s;
-    U8 * const send = s + *len;
-    U8 *d;
+    U8 * first_variant;
 
     PERL_ARGS_ASSERT_UTF8_TO_BYTES;
     PERL_UNUSED_CONTEXT;
 
-    /* ensure valid UTF-8 and chars < 256 before updating string */
+    /* This is a no-op if no variants at all in the input */
+    if (is_utf8_invariant_string_loc(s, *len, (const U8 **) &first_variant)) {
+        return s;
+    }
+
+    {
+    U8 * const save = s;
+    U8 * const send = s + *len;
+    U8 * d;
+
+    /* Nothing before the first variant needs to be changed, so start the real
+     * work there */
+    s = first_variant;
     while (s < send) {
         if (! UTF8_IS_INVARIANT(*s)) {
             if (! UTF8_IS_NEXT_CHAR_DOWNGRADEABLE(s, send)) {
@@ -1939,7 +1949,7 @@ Perl_utf8_to_bytes(pTHX_ U8 *s, STRLEN *len)
         s++;
     }
 
-    d = s = save;
+    d = s = first_variant;
     while (s < send) {
        U8 c = *s++;
        if (! UVCHR_IS_INVARIANT(c)) {
@@ -1952,6 +1962,7 @@ Perl_utf8_to_bytes(pTHX_ U8 *s, STRLEN *len)
     *d = '\0';
     *len = d - save;
     return save;
+    }
 }
 
 /*