regex free up bit in ANYOF node
authorKarl Williamson <public@khwilliamson.com>
Fri, 12 Nov 2010 03:07:09 +0000 (20:07 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Mon, 22 Nov 2010 21:32:50 +0000 (13:32 -0800)
This patch causes all locale ANYOF nodes to have a class bitmap (4
bytes) even if they don't have a class (such as \w, \d, [:posix:]).
This frees up a bit in the flags field that was used to signal if the
node had the bitmap.  I intend to use it instead to signal that loading
a swash, which is slow, can be bypassed.  Thus this is a time/space
tradeoff, applicable to not just locale nodes: adding a word to the
locale nodes saves time for all nodes.

I added the ANYOF_CLASS_TEST_ANY_SET() macro to determine quickly if
there are actually any classes in the node.

Minimal code was changed, so this can be easily reversed if another bit
frees up.

Another possibility is to share with the ANYOF_EOS bit instead, as this
is used just in the optimizer's start class, and only in regcomp.c.  But
this requires more careful coding.

Another possibility is to add a byte (hence likely at least 4 because of
alignment issues) to store extra flags.

And still another possibility is to add just the byte for the start
class, which would not need to affect other ANYOF nodes, since the EOS
bit is not used outside regcomp.c.  But various routines in regcomp
assume that the start class and other ANYOF nodes are interchangeable,
so this option would require more code changes.

regcomp.c
regcomp.h
regexec.c

index 787517b..26d480f 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -3572,7 +3572,8 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
                        goto do_default;
                    if (flags & SCF_DO_STCLASS_OR) { /* Everything but \n */
                        value = (ANYOF_BITMAP_TEST(data->start_class,'\n')
-                                || (data->start_class->flags & ANYOF_CLASS));
+                                || ((data->start_class->flags & ANYOF_CLASS)
+                                     && ANYOF_CLASS_TEST_ANY_SET(data->start_class)));
                        cl_anything(pRExC_state, data->start_class);
                    }
                    if (flags & SCF_DO_STCLASS_AND || !value)
@@ -9519,7 +9520,7 @@ Perl_regprop(pTHX_ const regexp *prog, SV *sv, const regnode *o)
         
         EMIT_ANYOF_TEST_SEPARATOR(do_sep,sv,flags);
         /* output any special charclass tests (used mostly under use locale) */
-       if (o->flags & ANYOF_CLASS)
+       if (o->flags & ANYOF_CLASS && ANYOF_CLASS_TEST_ANY_SET(o))
            for (i = 0; i < (int)(sizeof(anyofs)/sizeof(char*)); i++)
                if (ANYOF_CLASS_TEST(o,i)) {
                    sv_catpv(sv, anyofs[i]);
index 3e54110..7b73b02 100644 (file)
--- a/regcomp.h
+++ b/regcomp.h
@@ -319,7 +319,8 @@ struct regnode_charclass_class {
 #define ANYOF_INVERT           0x04
 
 /* CLASS is never set unless LOCALE is too: has runtime \d, \w, [:posix:], ... */
-#define ANYOF_CLASS            0x08
+/* For now, set it always when LOCALE is set, to save a bit for other uses. */
+#define ANYOF_CLASS     ANYOF_LOCALE
 #define ANYOF_LARGE      ANYOF_CLASS    /* Same; name retained for back compat */
 
 /* EOS used for regstclass only */
@@ -396,6 +397,12 @@ struct regnode_charclass_class {
 #define ANYOF_CLASS_CLEAR(p, c)        (ANYOF_CLASS_BYTE(p, c) &= ~ANYOF_BIT(c))
 #define ANYOF_CLASS_TEST(p, c) (ANYOF_CLASS_BYTE(p, c) &   ANYOF_BIT(c))
 
+/* Quicker way to see if there are actually any tests.  This is because
+ * currently the set of tests can be empty even when the class bitmap is
+ * allocated */
+#define ANYOF_CLASS_TEST_ANY_SET(p)    /* assumes sizeof(p) = 4 */       \
+       memNE (((struct regnode_charclass_class*)(p))->classflags, "0000", ANYOF_CLASS_SIZE)
+
 #define ANYOF_CLASS_ZERO(ret)  Zero(((struct regnode_charclass_class*)(ret))->classflags, ANYOF_CLASSBITMAP_SIZE, char)
 #define ANYOF_BITMAP_ZERO(ret) Zero(((struct regnode_charclass*)(ret))->bitmap, ANYOF_BITMAP_SIZE, char)
 
index a6da6ce..f541d9b 100644 (file)
--- a/regexec.c
+++ b/regexec.c
@@ -6260,7 +6260,7 @@ S_reginclass(pTHX_ const regexp * const prog, register const regnode * const n,
                match = TRUE;
        }
        
-       if (!match && (flags & ANYOF_CLASS)) {
+       if (!match && (flags & ANYOF_CLASS) && ANYOF_CLASS_TEST_ANY_SET(n)) {
            PL_reg_flags |= RF_tainted;
            if (
                (ANYOF_CLASS_TEST(n, ANYOF_ALNUM)   &&  isALNUM_LC(c))  ||