QRegularExpression: add an option to prevent automatic optimization

If a user doesn't like that QRegularExpression might do an
uncontrolled CPU/memory spike when it decides to optimize a pattern,
offer a way to disable the automatic optimization.

Change-Id: I38a98a3bfb239cfad9f977b0eeb75903268e747f
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Giuseppe D'Angelo 2014-04-29 20:45:45 +02:00 committed by The Qt Project
parent 260f24228b
commit 5b300a1526
2 changed files with 27 additions and 8 deletions

View File

@ -705,6 +705,17 @@ QT_BEGIN_NAMESPACE
JIT-compiled) on its first usage, instead of after a certain (undefined) JIT-compiled) on its first usage, instead of after a certain (undefined)
number of usages. See also \l{QRegularExpression::}{optimize()}. number of usages. See also \l{QRegularExpression::}{optimize()}.
This enum value has been introduced in Qt 5.4. This enum value has been introduced in Qt 5.4.
\value DontAutomaticallyOptimizeOption
Regular expressions are automatically optimized after a
certain number of usages; setting this option prevents such
optimizations, therefore avoiding possible unpredictable spikes in
CPU and memory usage. If both this option and the
\c{OptimizeOnFirstUsageOption} option are set, then this option takes
precedence. Note: this option will still let the regular expression
to be optimized by manually calling
\l{QRegularExpression::}{optimize()}. This enum value has been
introduced in Qt 5.4.
*/ */
/*! /*!
@ -1108,7 +1119,10 @@ static bool isJitEnabled()
setting the studyData member variable to the result of the study. It gets setting the studyData member variable to the result of the study. It gets
called by doMatch() every time a match is performed. As of now, the called by doMatch() every time a match is performed. As of now, the
optimizations on the pattern are performed after a certain number of usages optimizations on the pattern are performed after a certain number of usages
(i.e. the qt_qregularexpression_optimize_after_use_count constant). (i.e. the qt_qregularexpression_optimize_after_use_count constant) unless
the DontAutomaticallyOptimizeOption option is set on the QRegularExpression
object, or anyhow by calling optimize() (which will pass
ImmediateOptimizeOption).
Notice that although the method is protected by a mutex, one thread may Notice that although the method is protected by a mutex, one thread may
invoke this function and return immediately (i.e. not study the pattern, invoke this function and return immediately (i.e. not study the pattern,
@ -1248,13 +1262,15 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
matchType, matchOptions, matchType, matchOptions,
capturingCount + 1); capturingCount + 1);
const OptimizePatternOption optimizePatternOption = if (!(patternOptions & QRegularExpression::DontAutomaticallyOptimizeOption)) {
(patternOptions & QRegularExpression::OptimizeOnFirstUsageOption) const OptimizePatternOption optimizePatternOption =
? ImmediateOptimizeOption (patternOptions & QRegularExpression::OptimizeOnFirstUsageOption)
: LazyOptimizeOption; ? ImmediateOptimizeOption
: LazyOptimizeOption;
// this is mutex protected // this is mutex protected
const_cast<QRegularExpressionPrivate *>(this)->optimizePattern(optimizePatternOption); const_cast<QRegularExpressionPrivate *>(this)->optimizePattern(optimizePatternOption);
}
// work with a local copy of the study data, as we are running pcre_exec // work with a local copy of the study data, as we are running pcre_exec
// potentially more than once, and we don't want to run call it // potentially more than once, and we don't want to run call it
@ -2370,6 +2386,8 @@ QDebug operator<<(QDebug debug, QRegularExpression::PatternOptions patternOption
flags.append("UseUnicodePropertiesOption|"); flags.append("UseUnicodePropertiesOption|");
if (patternOptions & QRegularExpression::OptimizeOnFirstUsageOption) if (patternOptions & QRegularExpression::OptimizeOnFirstUsageOption)
flags.append("OptimizeOnFirstUsageOption|"); flags.append("OptimizeOnFirstUsageOption|");
if (patternOptions & QRegularExpression::DontAutomaticallyOptimizeOption)
flags.append("DontAutomaticallyOptimizeOption|");
flags.chop(1); flags.chop(1);
} }

View File

@ -70,7 +70,8 @@ public:
InvertedGreedinessOption = 0x0010, InvertedGreedinessOption = 0x0010,
DontCaptureOption = 0x0020, DontCaptureOption = 0x0020,
UseUnicodePropertiesOption = 0x0040, UseUnicodePropertiesOption = 0x0040,
OptimizeOnFirstUsageOption = 0x0080 OptimizeOnFirstUsageOption = 0x0080,
DontAutomaticallyOptimizeOption = 0x0100
}; };
Q_DECLARE_FLAGS(PatternOptions, PatternOption) Q_DECLARE_FLAGS(PatternOptions, PatternOption)