internal optimizations done by the regular expression engine, this will
take a painfully long time to run:
- 'aaaaaaaaaaaa' =~ /((a{0,5}){0,5}){0,5}[c]/
-
-And if you used C<*>'s instead of limiting it to 0 through 5 matches,
-then it would take forever--or until you ran out of stack space.
+ 'aaaaaaaaaaaa' =~ /((a{0,5}){0,5})*[c]/
+
+And if you used C<*>'s in the internal groups instead of limiting them
+to 0 through 5 matches, then it would take forever--or until you ran
+out of stack space. Moreover, these internal optimizations are not
+always applicable. For example, if you put C<{0,5}> instead of C<*>
+on the external group, no current optimization is applicable, and the
+match takes a long time to finish.
A powerful tool for optimizing such beasts is what is known as an
"independent group",
#define SCF_DO_STCLASS_AND 0x0800
#define SCF_DO_STCLASS_OR 0x1000
#define SCF_DO_STCLASS (SCF_DO_STCLASS_AND|SCF_DO_STCLASS_OR)
+#define SCF_WHILEM_VISITED_POS 0x2000
#define RF_utf8 8
#define UTF (PL_reg_flags & RF_utf8)
data_fake.start_class = &this_class;
f = SCF_DO_STCLASS_AND;
}
+ if (flags & SCF_WHILEM_VISITED_POS)
+ f |= SCF_WHILEM_VISITED_POS;
/* we suppose the run is continuous, last=next...*/
minnext = study_chunk(pRExC_state, &scan, &deltanext,
next, &data_fake, f);
f |= SCF_DO_STCLASS_AND;
f &= ~SCF_DO_STCLASS_OR;
}
+ /* These are the cases when once a subexpression
+ fails at a particular position, it cannot succeed
+ even after backtracking at the enclosing scope.
+
+ XXXX what if minimal match and we are at the
+ initial run of {n,m}? */
+ if ((mincount != maxcount - 1) && (maxcount != REG_INFTY))
+ f &= ~SCF_WHILEM_VISITED_POS;
/* This will finish on WHILEM, setting scan, or on NULL: */
minnext = study_chunk(pRExC_state, &scan, &deltanext, last, data,
}
#endif
/* Optimize again: */
- study_chunk(pRExC_state, &nxt1, &deltanext, nxt, NULL, 0);
+ study_chunk(pRExC_state, &nxt1, &deltanext, nxt,
+ NULL, 0);
}
else
oscan->flags = 0;
}
- else if (OP(oscan) == CURLYX && data && ++data->whilem_c < 16) {
- /* This stays as CURLYX, and can put the count/of pair. */
+ else if ((OP(oscan) == CURLYX)
+ && (flags & SCF_WHILEM_VISITED_POS)
+ /* See the comment on a similar expression above.
+ However, this time it not a subexpression
+ we care about, but the expression itself. */
+ && (maxcount == REG_INFTY)
+ && data && ++data->whilem_c < 16) {
+ /* This stays as CURLYX, we can put the count/of pair. */
/* Find WHILEM (as in regexec.c) */
regnode *nxt = oscan + NEXT_OFF(oscan);
&& OP(scan) == IFMATCH ) { /* Lookahead */
cl_init(pRExC_state, &intrnl);
data_fake.start_class = &intrnl;
- f = SCF_DO_STCLASS_AND;
+ f |= SCF_DO_STCLASS_AND;
}
+ if (flags & SCF_WHILEM_VISITED_POS)
+ f |= SCF_WHILEM_VISITED_POS;
next = regnext(scan);
nscan = NEXTOPER(NEXTOPER(scan));
minnext = study_chunk(pRExC_state, &nscan, &deltanext, last, &data_fake, f);
data->flags |= SF_HAS_EVAL;
if (data)
data->whilem_c = data_fake.whilem_c;
- if (f) {
+ if (f & SCF_DO_STCLASS_AND) {
int was = (data->start_class->flags & ANYOF_EOS);
cl_and(data->start_class, &intrnl);
data.last_closep = &last_close;
minlen = study_chunk(pRExC_state, &first, &fake, scan + RExC_size, /* Up to end */
- &data, SCF_DO_SUBSTR | stclass_flag);
+ &data, SCF_DO_SUBSTR | SCF_WHILEM_VISITED_POS | stclass_flag);
if ( RExC_npar == 1 && data.longest == &(data.longest_fixed)
&& data.last_start_min == 0 && data.last_end > 0
&& !RExC_seen_zerolen
cl_init(pRExC_state, &ch_class);
data.start_class = &ch_class;
data.last_closep = &last_close;
- minlen = study_chunk(pRExC_state, &scan, &fake, scan + RExC_size, &data, SCF_DO_STCLASS_AND);
+ minlen = study_chunk(pRExC_state, &scan, &fake, scan + RExC_size, &data, SCF_DO_STCLASS_AND|SCF_WHILEM_VISITED_POS);
r->check_substr = r->anchored_substr = r->float_substr = Nullsv;
if (!(data.start_class->flags & ANYOF_EOS)
&& !cl_is_anything(data.start_class)) {