S_sv_pos_u2b_cached now updates the UTF-8 length cache if at the end of string.
authorNicholas Clark <nick@ccl4.org>
Mon, 12 Jul 2010 10:38:31 +0000 (11:38 +0100)
committerNicholas Clark <nick@ccl4.org>
Mon, 12 Jul 2010 12:43:19 +0000 (13:43 +0100)
Pass in a boolean to S_sv_pos_u2b_forwards, which sets it to true if it
discovers that the UTF-8 offset is at (or after) the end of the string.
This can only happen if we don't already know the SV's length (in Unicode
characters), because if we know it, we always call S_sv_pos_u2b_midway().

embed.fnc
proto.h
sv.c

index 99f4b13..31de4ce 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -1884,7 +1884,8 @@ s |int    |sv_2iuv_non_preserve   |NN SV *const sv
 sR     |I32    |expect_number  |NN char **const pattern
 #
 sn     |STRLEN |sv_pos_u2b_forwards|NN const U8 *const start \
-               |NN const U8 *const send|NN STRLEN *const uoffset
+               |NN const U8 *const send|NN STRLEN *const uoffset \
+               |NN bool *const at_end
 sn     |STRLEN |sv_pos_u2b_midway|NN const U8 *const start \
                |NN const U8 *send|STRLEN uoffset|const STRLEN uend
 s      |STRLEN |sv_pos_u2b_cached|NN SV *const sv|NN MAGIC **const mgp \
diff --git a/proto.h b/proto.h
index 6fc11dd..f90c131 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -5814,12 +5814,13 @@ STATIC I32      S_expect_number(pTHX_ char **const pattern)
        assert(pattern)
 
 #
-STATIC STRLEN  S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send, STRLEN *const uoffset)
+STATIC STRLEN  S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send, STRLEN *const uoffset, bool *const at_end)
                        __attribute__nonnull__(1)
                        __attribute__nonnull__(2)
-                       __attribute__nonnull__(3);
+                       __attribute__nonnull__(3)
+                       __attribute__nonnull__(4);
 #define PERL_ARGS_ASSERT_SV_POS_U2B_FORWARDS   \
-       assert(start); assert(send); assert(uoffset)
+       assert(start); assert(send); assert(uoffset); assert(at_end)
 
 STATIC STRLEN  S_sv_pos_u2b_midway(const U8 *const start, const U8 *send, STRLEN uoffset, const STRLEN uend)
                        __attribute__nonnull__(1)
diff --git a/sv.c b/sv.c
index a3bc6e1..ce16db6 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -6077,7 +6077,7 @@ Perl_sv_len_utf8(pTHX_ register SV *const sv)
    offset.  */
 static STRLEN
 S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
-                     STRLEN *const uoffset_p)
+                     STRLEN *const uoffset_p, bool *const at_end)
 {
     const U8 *s = start;
     STRLEN uoffset = *uoffset_p;
@@ -6088,7 +6088,11 @@ S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
        --uoffset;
        s += UTF8SKIP(s);
     }
-    if (s > send) {
+    if (s == send) {
+       *at_end = TRUE;
+    }
+    else if (s > send) {
+       *at_end = TRUE;
        /* This is the existing behaviour. Possibly it should be a croak, as
           it's actually a bounds error  */
        s = send;
@@ -6145,6 +6149,7 @@ S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start
 {
     STRLEN boffset = 0; /* Actually always set, but let's keep gcc happy.  */
     bool found = FALSE;
+    bool at_end = FALSE;
 
     PERL_ARGS_ASSERT_SV_POS_U2B_CACHED;
 
@@ -6185,7 +6190,7 @@ S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start
                    uoffset -= uoffset0;
                    boffset = boffset0
                        + sv_pos_u2b_forwards(start + boffset0,
-                                               send, &uoffset);
+                                             send, &uoffset, &at_end);
                    uoffset += uoffset0;
                }
            }
@@ -6227,7 +6232,7 @@ S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start
        STRLEN real_boffset;
        uoffset -= uoffset0;
        real_boffset = boffset0 + sv_pos_u2b_forwards(start + boffset0,
-                                                     send, &uoffset);
+                                                     send, &uoffset, &at_end);
        uoffset += uoffset0;
 
        if (found && PL_utf8cache < 0) {
@@ -6244,8 +6249,12 @@ S_sv_pos_u2b_cached(pTHX_ SV *const sv, MAGIC **const mgp, const U8 *const start
        boffset = real_boffset;
     }
 
-    if (PL_utf8cache)
-       utf8_mg_pos_cache_update(sv, mgp, boffset, uoffset, send - start);
+    if (PL_utf8cache) {
+       if (at_end)
+           utf8_mg_len_cache_update(sv, mgp, uoffset);
+       else
+           utf8_mg_pos_cache_update(sv, mgp, boffset, uoffset, send - start);
+    }
     return boffset;
 }