Find optimizations for /[[:posix:]]/a
authorKarl Williamson <khw@cpan.org>
Thu, 1 Nov 2018 07:43:39 +0000 (01:43 -0600)
committerKarl Williamson <khw@cpan.org>
Fri, 16 Nov 2018 17:48:18 +0000 (10:48 -0700)
Various optimizations are done when the regular expression compiler sees
a bracketed character class.  For example, /[a]/ is optimized into /a/.
This wasn't done for the various POSIX classes under /a, as the speed of
the operations of using a regular bracketed class (which uses a bitmap)
and of an optimized version (which uses a specialized opcode for the
POSIX class) is similar.  The only advantage would have been that the
specialized opcode is 1/10 the size of the bitmap.  But the optimization
in general couldn't come until the second pass, after the size had
already been calculated and space allocated.  So there was no savings.

But now that there is no separate sizing pass, doing the optimization
actually will save space.

regcomp.c
t/re/anyof.t

index b8265a1..a7f5790 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -18387,10 +18387,8 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
      * up less room and generally fewer operations to execute than ANYOF nodes.
      * Above, we checked for and optimized into some such equivalents for
      * certain common classes that are easy to test.  Getting to this point in
-     * the code means that the class didn't get optimized there.  Since this
-     * code is only executed in Pass 2, it is too late to save space--it has
-     * been allocated in Pass 1, and currently isn't given back.  XXX Why not?
-     * But turning things into an EXACTish node can allow the optimizer to join
+     * the code means that the class didn't get optimized there.
+     * Turning things into an EXACTish node can allow the optimizer to join
      * it to any adjacent such nodes.  And if the class is equivalent to things
      * like /./, expensive run-time swashes can be avoided.  Now that we have
      * more complete information, we can find things necessarily missed by the
@@ -18497,22 +18495,12 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
                 op = NASCII;
                 *flagp |= HASWIDTH|SIMPLE;
             }
-            else if (invlist_highest(cp_list) >= 0x2029) {
+            else {
 
                 /* Then try the other POSIX classes.  The POSIXA ones are about
-                 * the same speed as ANYOF ops, but the ones that have
-                 * above-Latin1 code point matches are somewhat faster than
-                 * ANYOF.  So optimize those, but don't bother with the POSIXA
-                 * ones nor [:cntrl:] which has no above-Latin1 matches.  If
-                 * this ANYOF node has a lower highest possible matching code
-                 * point than any of the XPosix ones, we know that it can't
-                 * possibly be the same as any of them, so we can avoid
-                 * executing this code.  The 0x2029 above for the lowest max
-                 * was determined by manual inspection of the classes, and
-                 * comes from \v.  Suppose Unicode in a later version adds a
-                 * higher code point to \v.  All that means is that this code
-                 * can be executed unnecessarily.  It will still give the
-                 * correct answer. */
+                 * the same speed as ANYOF ops, but take less room; the ones
+                 * that have above-Latin1 code point matches are somewhat
+                 * faster than ANYOF. */
 
                 for (posix_class = 0;
                      posix_class <= _HIGHEST_REGCOMP_DOT_H_SYNC;
@@ -18520,13 +18508,23 @@ S_regclass(pTHX_ RExC_state_t *pRExC_state, I32 *flagp, U32 depth,
                 {
                     int try_inverted;
 
-                    if (posix_class == _CC_CNTRL) {
-                        continue;
-                    }
-
                     for (try_inverted = 0; try_inverted < 2; try_inverted++) {
 
-                        /* Check if matches normal or inverted */
+                        /* Check if matches POSIXA, normal or inverted */
+                        if (PL_Posix_ptrs[posix_class]) {
+                            if (_invlistEQ(cp_list,
+                                           PL_Posix_ptrs[posix_class],
+                                           try_inverted))
+                            {
+                                op = (try_inverted)
+                                    ? NPOSIXA
+                                    : POSIXA;
+                                *flagp |= HASWIDTH|SIMPLE;
+                                goto found_posix;
+                            }
+                        }
+
+                        /* Check if matches POSIXU, normal or inverted */
                         if (_invlistEQ(cp_list,
                                        PL_XPosix_ptrs[posix_class],
                                        try_inverted))
index 6970a40..b452243 100644 (file)
@@ -35,7 +35,7 @@ my @tests = (
     '[^\S ]' => 'ANYOFD[\t\n\x0B\f\r{utf8}\x85\xA0][1680 2000-200A 2028-2029 202F 205F 3000]',
     '[^\n\r]' => 'ANYOF[^\n\r][0100-INFINITY]',
     '[^\/\|,\$\%%\@\ \%"\<\>\:\#\&\*\{\}\[\]\(\)]' => 'ANYOF[^ "#$%&()*,/:<>@\[\]\{|\}][0100-INFINITY]',
-    '[^[:^print:][:^ascii:]]' => 'ANYOF[\x20-\x7E]',
+    '[^[:^print:][:^ascii:]]' => 'POSIXA[:print:]',
     '[ [:blank:]]' => 'ANYOFD[\t {utf8}\xA0][1680 2000-200A 202F 205F 3000]',
     '[_[:^blank:]]' => 'ANYOFD[^\t {utf8}\xA0][0100-167F 1681-1FFF 200B-202E 2030-205E 2060-2FFF 3001-INFINITY]',
     '[\xA0[:^blank:]]' => 'ANYOF[^\t ][0100-167F 1681-1FFF 200B-202E 2030-205E 2060-2FFF 3001-INFINITY]',