Optimize QLoggingSettingsParser

Factor the line parsing into a separate function, parseNextLine(),
taking a QStringRef.

In setContent(QTextStream&), use the new readLineInto() function to
re-use the capacity of a single QString for all lines.

In setContent(QString), use splitRef() to split the lines.

In either function, pass each line to parseNextLine().

In order to port all the parsing to QStringRef, I needed to make some
semantic changes: the old code removed all whitespace right at the
beginning. This is not possible with QStringRef. It also didn't feel
right, since a line like

   [    r u  l e s ]

would successfully parse as the section named "rules".

I added trimmed() calls at the beginning, and around the valueStr and
pattern extraction, which should be good enough.

Also, when a section is found, don't store it anymore. Instead, only
store whether it was the [rules] section, because that's all we'll
test for. That way, we don't have to convert QStringRefs to QString
just to store them across parseNextLine() calls.

Replace the setSection() function with setImplicitRulesSection(),
because "rules" is all that was ever passed.

This is private API, we can bring back some of the dropped flexibility
later, as needed.

[ChangeLog][Important Behavior Changes] Logging rules can no longer
contain arbitrary whitespace such as within a category identifier.

Change-Id: Ic26cd23c71f5c810b37ef4b972354ac31d3408fe
Reviewed-by: Kai Koehne <kai.koehne@qt.io>
This commit is contained in:
Marc Mutz 2017-02-07 22:29:45 +01:00
parent db29042588
commit 46c66bce5d
2 changed files with 50 additions and 38 deletions

View File

@ -186,9 +186,10 @@ void QLoggingRule::parse(const QStringRef &pattern)
*/
void QLoggingSettingsParser::setContent(const QString &content)
{
QString content_ = content;
QTextStream stream(&content_, QIODevice::ReadOnly);
setContent(stream);
_rules.clear();
const auto lines = content.splitRef(QLatin1Char('\n'));
for (const auto &line : lines)
parseNextLine(line);
}
/*!
@ -198,42 +199,50 @@ void QLoggingSettingsParser::setContent(const QString &content)
void QLoggingSettingsParser::setContent(QTextStream &stream)
{
_rules.clear();
while (!stream.atEnd()) {
QString line = stream.readLine();
QString line;
while (stream.readLineInto(&line))
parseNextLine(QStringRef(&line));
}
// Remove all whitespace from line
line = line.simplified();
line.remove(QLatin1Char(' '));
/*!
\internal
Parses one line of the configuation file
*/
// comment
if (line.startsWith(QLatin1Char(';')))
continue;
void QLoggingSettingsParser::parseNextLine(QStringRef line)
{
// Remove whitespace at start and end of line:
line = line.trimmed();
if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
// new section
_section = line.mid(1, line.size() - 2);
continue;
}
// comment
if (line.startsWith(QLatin1Char(';')))
return;
if (_section.compare(QLatin1String("rules"), Qt::CaseInsensitive) == 0) {
int equalPos = line.indexOf(QLatin1Char('='));
if (equalPos != -1) {
if (line.lastIndexOf(QLatin1Char('=')) == equalPos) {
const QStringRef pattern = line.leftRef(equalPos);
const QStringRef valueStr = line.midRef(equalPos + 1);
int value = -1;
if (valueStr == QLatin1String("true"))
value = 1;
else if (valueStr == QLatin1String("false"))
value = 0;
QLoggingRule rule(pattern, (value == 1));
if (rule.flags != 0 && (value != -1))
_rules.append(rule);
else
warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
} else {
if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
// new section
auto sectionName = line.mid(1, line.size() - 2).trimmed();
m_inRulesSection = sectionName.compare(QLatin1String("rules"), Qt::CaseInsensitive) == 0;
return;
}
if (m_inRulesSection) {
int equalPos = line.indexOf(QLatin1Char('='));
if (equalPos != -1) {
if (line.lastIndexOf(QLatin1Char('=')) == equalPos) {
const auto pattern = line.left(equalPos).trimmed();
const auto valueStr = line.mid(equalPos + 1).trimmed();
int value = -1;
if (valueStr == QLatin1String("true"))
value = 1;
else if (valueStr == QLatin1String("false"))
value = 0;
QLoggingRule rule(pattern, (value == 1));
if (rule.flags != 0 && (value != -1))
_rules.append(rule);
else
warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
}
} else {
warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
}
}
}
@ -286,7 +295,7 @@ void QLoggingRegistry::init()
if (!rulesSrc.isEmpty()) {
QTextStream stream(rulesSrc);
QLoggingSettingsParser parser;
parser.setSection(QStringLiteral("Rules"));
parser.setImplicitRulesSection(true);
parser.setContent(stream);
er += parser.rules();
}
@ -350,7 +359,7 @@ void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat)
void QLoggingRegistry::setApiRules(const QString &content)
{
QLoggingSettingsParser parser;
parser.setSection(QStringLiteral("Rules"));
parser.setImplicitRulesSection(true);
parser.setContent(content);
if (qtLoggingDebug())

View File

@ -93,7 +93,7 @@ Q_DECLARE_TYPEINFO(QLoggingRule, Q_MOVABLE_TYPE);
class Q_AUTOTEST_EXPORT QLoggingSettingsParser
{
public:
void setSection(const QString &section) { _section = section; }
void setImplicitRulesSection(bool inRulesSection) { m_inRulesSection = inRulesSection; }
void setContent(const QString &content);
void setContent(QTextStream &stream);
@ -101,7 +101,10 @@ public:
QVector<QLoggingRule> rules() const { return _rules; }
private:
QString _section;
void parseNextLine(QStringRef line);
private:
bool m_inRulesSection = false;
QVector<QLoggingRule> _rules;
};