Commit b5739e36 authored by Leandro Melo's avatar Leandro Melo

Gen. highlighter: Improve performance (reg. exp.)

Cache matches of the RegExprRule to avoid unnecessary calls.
This is essentially the same optimization existent in Kate.

A colateral effect of this implementation is a mechanism to
notify the rules when a progress (highlight of the current
line) is finished.
parent 6a6d9dac
......@@ -28,6 +28,7 @@
**************************************************************************/
#include "progressdata.h"
#include "rule.h"
#include <QtCore/QtGlobal>
......@@ -43,6 +44,12 @@ ProgressData::ProgressData() :
m_willContinueLine(false)
{}
ProgressData::~ProgressData()
{
foreach (Rule *rule, m_trackedRules)
rule->progressFinished();
}
void ProgressData::setOffset(const int offset)
{ m_offset = offset; }
......@@ -102,3 +109,8 @@ void ProgressData::setCaptures(const QStringList &captures)
const QStringList &ProgressData::captures() const
{ return m_captures; }
void ProgressData::trackRule(Rule *rule)
{
m_trackedRules.append(rule);
}
......@@ -35,10 +35,13 @@
namespace TextEditor {
namespace Internal {
class Rule;
class ProgressData
{
public:
ProgressData();
~ProgressData();
void setOffset(const int offset);
int offset() const;
......@@ -66,6 +69,8 @@ public:
void setCaptures(const QStringList &captures);
const QStringList &captures() const;
void trackRule(Rule *rule);
private:
int m_offset;
int m_savedOffset;
......@@ -74,6 +79,7 @@ private:
bool m_closingBraceMatchAtNonEnd;
bool m_willContinueLine;
QStringList m_captures;
QList<Rule *> m_trackedRules;
};
} // namespace Internal
......
......@@ -162,7 +162,7 @@ bool Rule::charPredicateMatchSucceed(const QString &text,
return predicateMatchSucceed(text, length, progress, std::ptr_fun(predicate));
}
bool Rule::matchSucceed(const QString &text, const int length, ProgressData *progress) const
bool Rule::matchSucceed(const QString &text, const int length, ProgressData *progress)
{
if (m_firstNonSpace && !progress->isOnlySpacesSoFar())
return false;
......@@ -187,6 +187,9 @@ bool Rule::matchSucceed(const QString &text, const int length, ProgressData *pro
Rule *Rule::clone() const
{ return doClone(); }
void Rule::progressFinished()
{ doProgressFinished(); }
bool Rule::matchCharacter(const QString &text,
const int length,
ProgressData *progress,
......
......@@ -74,10 +74,12 @@ public:
void setDefinition(const QSharedPointer<HighlightDefinition> &definition);
const QSharedPointer<HighlightDefinition> &definition() const;
bool matchSucceed(const QString &text, const int length, ProgressData *progress) const;
bool matchSucceed(const QString &text, const int length, ProgressData *progress);
Rule *clone() const;
void progressFinished();
protected:
bool charPredicateMatchSucceed(const QString &text,
const int length,
......@@ -128,12 +130,12 @@ protected:
static const QLatin1Char kClosingBrace;
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const = 0;
virtual bool doMatchSucceed(const QString &text, const int length, ProgressData *progress) = 0;
virtual Rule *doClone() const = 0;
virtual void doProgressFinished() {}
template <class predicate_t>
bool predicateMatchSucceed(const QString &text,
const int length,
......
......@@ -84,7 +84,7 @@ void DetectCharRule::doReplaceExpressions(const QStringList &captures)
bool DetectCharRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (matchCharacter(text, length, progress, m_char)) {
// This is to make code folding have a control flow style look in the case of braces.
......@@ -115,7 +115,7 @@ void Detect2CharsRule::doReplaceExpressions(const QStringList &captures)
bool Detect2CharsRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (matchCharacter(text, length, progress, m_char)) {
if (progress->offset() < length && matchCharacter(text, length, progress, m_char1, false))
......@@ -133,7 +133,7 @@ void AnyCharRule::setCharacterSet(const QString &s)
bool AnyCharRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
Q_UNUSED(length)
......@@ -163,7 +163,7 @@ void StringDetectRule::doReplaceExpressions(const QStringList &captures)
bool StringDetectRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (length - progress->offset() >= m_length) {
QString candidate = text.fromRawData(text.unicode() + progress->offset(), m_length);
......@@ -178,7 +178,11 @@ bool StringDetectRule::doMatchSucceed(const QString &text,
// RegExpr
void RegExprRule::setPattern(const QString &pattern)
{ m_expression.setPattern(pattern); }
{
if (pattern.startsWith(QLatin1Char('^')))
m_onlyBegin = true;
m_expression.setPattern(pattern);
}
void RegExprRule::setInsensitive(const QString &insensitive)
{ m_expression.setCaseSensitivity(toCaseSensitivity(!toBool(insensitive))); }
......@@ -193,23 +197,50 @@ void RegExprRule::doReplaceExpressions(const QStringList &captures)
m_expression.setPattern(s);
}
void RegExprRule::doProgressFinished()
{
m_isCached = false;
}
bool RegExprRule::isExactMatch(ProgressData *progress)
{
if (progress->offset() == m_offset && m_length > 0) {
progress->incrementOffset(m_length);
progress->setCaptures(m_captures);
return true;
}
return false;
}
bool RegExprRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
Q_UNUSED(length)
// This is not documented but a regular expression match is considered valid if it starts
// at the current position and if the match length is not zero.
// A regular expression match is considered valid if it happens at the current position
// and if the match length is not zero.
const int offset = progress->offset();
if (m_expression.indexIn(text, offset, QRegExp::CaretAtZero) == offset) {
if (m_expression.matchedLength() == 0)
if (offset > 0 && m_onlyBegin)
return false;
if (m_isCached) {
if (offset < m_offset || m_offset == -1 || m_length == 0)
return false;
progress->incrementOffset(m_expression.matchedLength());
progress->setCaptures(m_expression.capturedTexts());
return true;
if (isExactMatch(progress))
return true;
}
m_offset = m_expression.indexIn(text, offset, QRegExp::CaretAtOffset);
m_length = m_expression.matchedLength();
m_captures = m_expression.capturedTexts();
if (isExactMatch(progress))
return true;
m_isCached = true;
progress->trackRule(this);
return false;
}
......@@ -237,7 +268,7 @@ void KeywordRule::setList(const QString &listName)
bool KeywordRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
int current = progress->offset();
......@@ -263,7 +294,7 @@ bool KeywordRule::doMatchSucceed(const QString &text,
// Int
bool IntRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
const int offset = progress->offset();
......@@ -281,7 +312,7 @@ bool IntRule::doMatchSucceed(const QString &text,
}
// Float
bool FloatRule::doMatchSucceed(const QString &text, const int length, ProgressData *progress) const
bool FloatRule::doMatchSucceed(const QString &text, const int length, ProgressData *progress)
{
progress->saveOffset();
......@@ -322,7 +353,7 @@ bool FloatRule::doMatchSucceed(const QString &text, const int length, ProgressDa
// COctal
bool HlCOctRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (matchCharacter(text, length, progress, kZero)) {
// In the definition files the number matching rules which are more restrictive should
......@@ -345,7 +376,7 @@ bool HlCOctRule::doMatchSucceed(const QString &text,
// CHex
bool HlCHexRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (matchCharacter(text, length, progress, kZero)) {
const int offset = progress->offset();
......@@ -367,7 +398,7 @@ bool HlCHexRule::doMatchSucceed(const QString &text,
// CString
bool HlCStringCharRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (matchEscapeSequence(text, length, progress))
return true;
......@@ -384,7 +415,7 @@ bool HlCStringCharRule::doMatchSucceed(const QString &text,
// CChar
bool HlCCharRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (matchCharacter(text, length, progress, kSingleQuote)) {
if (progress->offset() < length) {
......@@ -419,7 +450,7 @@ void RangeDetectRule::setChar1(const QString &character)
bool RangeDetectRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (matchCharacter(text, length, progress, m_char)) {
while (progress->offset() < length) {
......@@ -436,7 +467,7 @@ bool RangeDetectRule::doMatchSucceed(const QString &text,
// LineContinue
bool LineContinueRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
if (progress->offset() != length - 1)
return false;
......@@ -456,7 +487,7 @@ DetectSpacesRule::DetectSpacesRule() : Rule(false)
bool DetectSpacesRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
return charPredicateMatchSucceed(text, length, progress, &QChar::isSpace);
}
......@@ -464,7 +495,7 @@ bool DetectSpacesRule::doMatchSucceed(const QString &text,
// DetectIdentifier
bool DetectIdentifierRule::doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const
ProgressData *progress)
{
// Identifiers are characterized by a letter or underscore as the first character and then
// zero or more word characters (\w*).
......
......@@ -34,7 +34,7 @@
#include "dynamicrule.h"
#include <QtCore/QChar>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QRegExp>
#include <QtCore/QSharedPointer>
......@@ -54,7 +54,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual DetectCharRule *doClone() const { return new DetectCharRule(*this); }
virtual void doReplaceExpressions(const QStringList &captures);
......@@ -72,7 +72,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual Detect2CharsRule *doClone() const { return new Detect2CharsRule(*this); }
virtual void doReplaceExpressions(const QStringList &captures);
......@@ -90,7 +90,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual AnyCharRule *doClone() const { return new AnyCharRule(*this); }
QString m_characterSet;
......@@ -107,7 +107,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual StringDetectRule *doClone() const { return new StringDetectRule(*this); }
virtual void doReplaceExpressions(const QStringList &captures);
......@@ -119,6 +119,7 @@ private:
class RegExprRule : public DynamicRule
{
public:
RegExprRule() : m_onlyBegin(false), m_isCached(false) {}
virtual ~RegExprRule() {}
void setPattern(const QString &pattern);
......@@ -128,10 +129,18 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual RegExprRule *doClone() const { return new RegExprRule(*this); }
virtual void doReplaceExpressions(const QStringList &captures);
virtual void doProgressFinished();
bool isExactMatch(ProgressData *progress);
bool m_onlyBegin;
bool m_isCached;
int m_offset;
int m_length;
QStringList m_captures;
QRegExp m_expression;
};
......@@ -147,7 +156,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual KeywordRule *doClone() const { return new KeywordRule(*this); }
bool m_overrideGlobal;
......@@ -163,7 +172,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual IntRule *doClone() const { return new IntRule(*this); }
};
......@@ -175,7 +184,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual FloatRule *doClone() const { return new FloatRule(*this); }
};
......@@ -187,7 +196,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual HlCOctRule *doClone() const { return new HlCOctRule(*this); }
};
......@@ -199,7 +208,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual HlCHexRule *doClone() const { return new HlCHexRule(*this); }
};
......@@ -211,7 +220,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual HlCStringCharRule *doClone() const { return new HlCStringCharRule(*this); }
};
......@@ -223,7 +232,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual HlCCharRule *doClone() const { return new HlCCharRule(*this); }
};
......@@ -238,7 +247,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual RangeDetectRule *doClone() const { return new RangeDetectRule(*this); }
QChar m_char;
......@@ -253,7 +262,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual LineContinueRule *doClone() const { return new LineContinueRule(*this); }
};
......@@ -266,7 +275,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual DetectSpacesRule *doClone() const { return new DetectSpacesRule(*this); }
};
......@@ -278,7 +287,7 @@ public:
private:
virtual bool doMatchSucceed(const QString &text,
const int length,
ProgressData *progress) const;
ProgressData *progress);
virtual DetectIdentifierRule *doClone() const { return new DetectIdentifierRule(*this); }
};
......
......@@ -105,8 +105,8 @@ private slots:
private:
void addCommonColumns() const;
void testMatch(const Rule &rule) const;
void testMatch(const Rule &rule, ProgressData *progress) const;
void testMatch(Rule *rule);
void testMatch(Rule *rule, ProgressData *progress);
void noMatchForInt() const;
void noMatchForFloat() const;
......@@ -138,17 +138,17 @@ void tst_SpecificRules::addCommonColumns() const
QTest::addColumn<bool>("will continue");
}
void tst_SpecificRules::testMatch(const Rule &rule) const
void tst_SpecificRules::testMatch(Rule *rule)
{
ProgressData progress;
testMatch(rule, &progress);
}
void tst_SpecificRules::testMatch(const Rule &rule, ProgressData *progress) const
void tst_SpecificRules::testMatch(Rule *rule, ProgressData *progress)
{
QFETCH(QString, s);
QTEST(rule.matchSucceed(s, s.length(), progress), "match");
QTEST(rule->matchSucceed(s, s.length(), progress), "match");
QTEST(progress->offset(), "offset");
QTEST(progress->isOnlySpacesSoFar(), "only spaces");
QTEST(progress->isWillContinueLine(), "will continue");
......@@ -160,7 +160,7 @@ void tst_SpecificRules::testDetectChar()
DetectCharRule rule;
rule.setChar(c);
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testDetectChar_data()
......@@ -186,7 +186,7 @@ void tst_SpecificRules::testDetect2Char()
rule.setChar(c);
rule.setChar1(c1);
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testDetect2Char_data()
......@@ -214,7 +214,7 @@ void tst_SpecificRules::testAnyChar()
AnyCharRule rule;
rule.setCharacterSet(chars);
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testAnyChar_data()
......@@ -245,7 +245,7 @@ void tst_SpecificRules::testStringDetect()
rule.setString(referenceString);
rule.setInsensitive(insensitive);
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testStringDetect_data()
......@@ -277,7 +277,7 @@ void tst_SpecificRules::testRegExpr()
rule.setInsensitive(insensitive);
rule.setMinimal(minimal);
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testRegExpr_data()
......@@ -322,7 +322,7 @@ void tst_SpecificRules::testRegExprOffsetIncremented()
ProgressData progress;
progress.setOffset(1);
testMatch(rule, &progress);
testMatch(&rule, &progress);
}
void tst_SpecificRules::testRegExprOffsetIncremented_data()
......@@ -388,7 +388,7 @@ void tst_SpecificRules::testKeywordGlobalSensitiveLocalSensitive()
rule.setInsensitive("false");
rule.setList("keywords");
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testKeywordGlobalSensitiveLocalSensitive_data()
......@@ -410,7 +410,7 @@ void tst_SpecificRules::testKeywordGlobalSensitiveLocalInsensitive()
rule.setInsensitive("true");
rule.setList("keywords");
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testKeywordGlobalSensitiveLocalInsensitive_data()
......@@ -432,7 +432,7 @@ void tst_SpecificRules::testKeywordGlobalInsensitiveLocalInsensitive()
rule.setInsensitive("true");
rule.setList("keywords");
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testKeywordGlobalInsensitiveLocalInsensitive_data()
......@@ -447,7 +447,7 @@ void tst_SpecificRules::testKeywordGlobalInsensitiveLocalSensitive()
rule.setInsensitive("false");
rule.setList("keywords");
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testKeywordGlobalInsensitiveLocalSensitive_data()
......@@ -510,7 +510,7 @@ void tst_SpecificRules::noMatchForNumber() const
void tst_SpecificRules::testInt()
{
IntRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testInt_data()
......@@ -534,7 +534,7 @@ void tst_SpecificRules::testInt_data()
void tst_SpecificRules::testFloat()
{
FloatRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testFloat_data()
......@@ -568,7 +568,7 @@ void tst_SpecificRules::testFloat_data()
void tst_SpecificRules::testCOctal()
{
HlCOctRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testCOctal_data()
......@@ -589,7 +589,7 @@ void tst_SpecificRules::testCOctal_data()
void tst_SpecificRules::testCHex()
{
HlCHexRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testCHex_data()
......@@ -609,7 +609,7 @@ void tst_SpecificRules::testCHex_data()
void tst_SpecificRules::testCString()
{
HlCStringCharRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testCString_data()
......@@ -656,7 +656,7 @@ void tst_SpecificRules::testCString_data()
void tst_SpecificRules::testCChar()
{
HlCCharRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testCChar_data()
......@@ -692,7 +692,7 @@ void tst_SpecificRules::testRangeDetect()
rule.setChar(c);
rule.setChar1(c1);
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testRangeDetect_data()
......@@ -719,7 +719,7 @@ void tst_SpecificRules::testRangeDetect_data()
void tst_SpecificRules::testLineContinue()
{
LineContinueRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testLineContinue_data()
......@@ -737,7 +737,7 @@ void tst_SpecificRules::testLineContinue_data()
void tst_SpecificRules::testDetectSpaces()
{
DetectSpacesRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testDetectSpaces_data()
......@@ -754,7 +754,7 @@ void tst_SpecificRules::testDetectSpaces_data()
void tst_SpecificRules::testDetectIdentifier()
{
DetectIdentifierRule rule;
testMatch(rule);
testMatch(&rule);
}
void tst_SpecificRules::testDetectIdentifier_data()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment