Some further optimizations in the qdoc code

Replace a lot of c strings with QLatin1String to avoid
utf conversions. Make one constant data structure static to
avoid it being recreated the whole time, and optimize our
tag replacement code.

Change-Id: I6513f3c70781a1bac658cbb3164c45d4cab36f57
Reviewed-by: Martin Smith <martin.smith@digia.com>
This commit is contained in:
Lars Knoll 2015-07-23 13:07:55 +02:00
parent 57bd6e67f7
commit 906ad92fbf
4 changed files with 113 additions and 134 deletions

View File

@ -49,6 +49,7 @@
#include <qiterator.h>
#include <qtextcodec.h>
#include <quuid.h>
#include <qmap.h>
QT_BEGIN_NAMESPACE
@ -71,11 +72,11 @@ static void addLink(const QString &linkTarget,
QString *res)
{
if (!linkTarget.isEmpty()) {
*res += "<a href=\"";
*res += QLatin1String("<a href=\"");
*res += linkTarget;
*res += "\">";
*res += QLatin1String("\">");
*res += nestedStuff;
*res += "</a>";
*res += QLatin1String("</a>");
}
else {
*res += nestedStuff;
@ -139,8 +140,8 @@ void HtmlGenerator::initializeGenerator(const Config &config)
*/
int i = 0;
while (defaults[i].key) {
formattingLeftMap().insert(defaults[i].key, defaults[i].left);
formattingRightMap().insert(defaults[i].key, defaults[i].right);
formattingLeftMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].left));
formattingRightMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].right));
i++;
}
@ -180,7 +181,7 @@ void HtmlGenerator::initializeGenerator(const Config &config)
projectDescription = config.getString(CONFIG_DESCRIPTION);
if (projectDescription.isEmpty() && !project.isEmpty())
projectDescription = project + " Reference Documentation";
projectDescription = project + QLatin1String(" Reference Documentation");
projectUrl = config.getString(CONFIG_URL);
tagFile_ = config.getString(CONFIG_TAGFILE);
@ -236,8 +237,8 @@ void HtmlGenerator::initializeGenerator(const Config &config)
headerStyles = config.getString(HtmlGenerator::format() + Config::dot + CONFIG_HEADERSTYLES);
QString prefix = CONFIG_QHP + Config::dot + project + Config::dot;
manifestDir = "qthelp://" + config.getString(prefix + "namespace");
manifestDir += QLatin1Char('/') + config.getString(prefix + "virtualFolder") + QLatin1Char('/');
manifestDir = QLatin1String("qthelp://") + config.getString(prefix + QLatin1String("namespace"));
manifestDir += QLatin1Char('/') + config.getString(prefix + QLatin1String("virtualFolder")) + QLatin1Char('/');
readManifestMetaContent(config);
examplesPath = config.getString(CONFIG_EXAMPLESINSTALLPATH);
if (!examplesPath.isEmpty())
@ -285,7 +286,7 @@ void HtmlGenerator::generateKeywordAnchors(const Node* node)
if (!node->doc().isEmpty()) {
const QList<Atom*>& keywords = node->doc().keywords();
foreach (Atom* a, keywords) {
out() << "<a name=\"" << Doc::canonicalTitle(a->string()) << "\"></a>";
out() << QLatin1String("<a name=\"") << Doc::canonicalTitle(a->string()) << QLatin1String("\"></a>");
}
}
}
@ -539,9 +540,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
else
out() << "variable";
QStringList words = str.split(QLatin1Char(' '));
if (!(words.first() == "contains" || words.first() == "specifies"
|| words.first() == "describes" || words.first() == "defines"
|| words.first() == "holds" || words.first() == "determines"))
if (!(words.first() == QLatin1String("contains") || words.first() == QLatin1String("specifies")
|| words.first() == QLatin1String("describes") || words.first() == QLatin1String("defines")
|| words.first() == QLatin1String("holds") || words.first() == QLatin1String("determines")))
out() << " holds ";
else
out() << ' ';
@ -666,20 +667,20 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
break;
case Atom::GeneratedList:
if (atom->string() == "annotatedclasses") {
if (atom->string() == QLatin1String("annotatedclasses")) {
generateAnnotatedList(relative, marker, qdb_->getCppClasses());
}
else if (atom->string() == "classes") {
else if (atom->string() == QLatin1String("classes")) {
generateCompactList(Generic, relative, qdb_->getCppClasses(), true, QStringLiteral(""));
}
else if (atom->string().contains("classes ")) {
QString rootName = atom->string().mid(atom->string().indexOf("classes") + 7).trimmed();
generateCompactList(Generic, relative, qdb_->getCppClasses(), true, rootName);
}
else if (atom->string() == "qmlbasictypes") {
else if (atom->string() == QLatin1String("qmlbasictypes")) {
generateCompactList(Generic, relative, qdb_->getQmlBasicTypes(), true, QStringLiteral(""));
}
else if (atom->string() == "qmltypes") {
else if (atom->string() == QLatin1String("qmltypes")) {
generateCompactList(Generic, relative, qdb_->getQmlTypes(), true, QStringLiteral(""));
}
else if (atom->string().contains("classesbymodule")) {
@ -694,40 +695,40 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
}
}
else if (atom->string() == "classhierarchy") {
else if (atom->string() == QLatin1String("classhierarchy")) {
generateClassHierarchy(relative, qdb_->getCppClasses());
}
else if (atom->string() == "obsoleteclasses") {
else if (atom->string() == QLatin1String("obsoleteclasses")) {
generateCompactList(Generic, relative, qdb_->getObsoleteClasses(), false, QStringLiteral("Q"));
}
else if (atom->string() == "obsoleteqmltypes") {
else if (atom->string() == QLatin1String("obsoleteqmltypes")) {
generateCompactList(Generic, relative, qdb_->getObsoleteQmlTypes(), false, QStringLiteral(""));
}
else if (atom->string() == "obsoletecppmembers") {
else if (atom->string() == QLatin1String("obsoletecppmembers")) {
generateCompactList(Obsolete, relative, qdb_->getClassesWithObsoleteMembers(), false, QStringLiteral("Q"));
}
else if (atom->string() == "obsoleteqmlmembers") {
else if (atom->string() == QLatin1String("obsoleteqmlmembers")) {
generateCompactList(Obsolete, relative, qdb_->getQmlTypesWithObsoleteMembers(), false, QStringLiteral(""));
}
else if (atom->string() == "functionindex") {
else if (atom->string() == QLatin1String("functionindex")) {
generateFunctionIndex(relative);
}
else if (atom->string() == "legalese") {
else if (atom->string() == QLatin1String("legalese")) {
generateLegaleseList(relative, marker);
}
else if (atom->string() == "overviews") {
else if (atom->string() == QLatin1String("overviews")) {
generateList(relative, marker, "overviews");
}
else if (atom->string() == "cpp-modules") {
else if (atom->string() == QLatin1String("cpp-modules")) {
generateList(relative, marker, "cpp-modules");
}
else if (atom->string() == "qml-modules") {
else if (atom->string() == QLatin1String("qml-modules")) {
generateList(relative, marker, "qml-modules");
}
else if (atom->string() == "namespaces") {
else if (atom->string() == QLatin1String("namespaces")) {
generateAnnotatedList(relative, marker, qdb_->getNamespaces());
}
else if (atom->string() == "related") {
else if (atom->string() == QLatin1String("related")) {
generateList(relative, marker, "related");
}
#if 0
@ -735,7 +736,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
This is not used in Qt5, as of 10/02/2014
Remove permanently if it is not missed.
*/
else if (atom->string() == "relatedinline") {
else if (atom->string() == QLatin1String("relatedinline")) {
const DocumentNode *dn = static_cast<const DocumentNode *>(relative);
if (dn && !dn->members().isEmpty()) {
// Reverse the list into the original scan order.
@ -1210,13 +1211,13 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
p2 = atom->string(1);
}
if (!p1.isEmpty()) {
if (p1 == "borderless")
if (p1 == QLatin1String("borderless"))
attr = p1;
else if (p1.contains("%"))
width = p1;
}
if (!p2.isEmpty()) {
if (p2 == "borderless")
if (p2 == QLatin1String("borderless"))
attr = p2;
else if (p2.contains("%"))
width = p2;
@ -3158,13 +3159,13 @@ void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const
{
CNMap cnm;
Node::Genus genus = Node::DontCare;
if (selector == "overviews")
if (selector == QLatin1String("overviews"))
genus = Node::DOC;
else if (selector == "cpp-modules")
else if (selector == QLatin1String("cpp-modules"))
genus = Node::CPP;
else if (selector == "qml-modules")
else if (selector == QLatin1String("qml-modules"))
genus = Node::QML;
else if (selector == "js-modules")
else if (selector == QLatin1String("js-modules"))
genus = Node::JS;
if (genus != Node::DontCare) {
NodeList nl;
@ -3409,6 +3410,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
{
QString src = markedCode;
QString html;
html.reserve(src.size());
QStringRef arg;
QStringRef par1;
@ -3421,62 +3423,30 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
static const QString linkTag("link");
// replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)"
// replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)"
// replace all "(<@(type|headerfile)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
bool done = false;
for (int i = 0, srcSize = src.size(); i < srcSize;) {
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
if (alignNames && !done) {
html += "</td><td class=\"memItemRight bottomAlign\">";
html += QLatin1String("</td><td class=\"memItemRight bottomAlign\">");
done = true;
}
i += 2;
if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
html += "<b>";
html += QLatin1String("<b>");
const Node* n = CodeMarker::nodeForString(par1.toString());
QString link = linkForNode(n, relative);
addLink(link, arg, &html);
html += "</b>";
html += QLatin1String("</b>");
}
else {
html += charLangle;
html += charAt;
}
}
else {
html += src.at(i++);
}
}
// replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)"
src = html;
html = QString();
for (int i = 0, srcSize = src.size(); i < srcSize;) {
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
const Node* n = qdb_->findFunctionNode(par1.toString(), relative, Node::DontCare);
QString link = linkForNode(n, relative);
addLink(link, arg, &html);
par1 = QStringRef();
}
else {
html += charLangle;
html += charAt;
}
}
else {
html += src.at(i++);
}
}
// replace all "(<@(type|headerfile)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
src = html;
html = QString();
for (int i=0, srcSize=src.size(); i<srcSize;) {
if (src.at(i) == charLangle && src.at(i+1) == charAt) {
i += 2;
bool handled = false;
if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
const Node* n = qdb_->findTypeNode(arg.toString(), relative);
html += QLatin1String("<span class=\"type\">");
@ -3489,7 +3459,6 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
else
addLink(linkForNode(n,relative), arg, &html);
html += QLatin1String("</span>");
handled = true;
}
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
@ -3502,9 +3471,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
else
html += arg;
}
handled = true;
}
if (!handled) {
else {
html += charLangle;
html += charAt;
}
@ -3527,60 +3495,68 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
// "</@(?:comment|preprocessor|string|char|number|op|type|name|keyword)>" -> "</span>"
src = html;
html = QString();
static const QString spanTags[] = {
"<@comment>", "<span class=\"comment\">",
"<@preprocessor>", "<span class=\"preprocessor\">",
"<@string>", "<span class=\"string\">",
"<@char>", "<span class=\"char\">",
"<@number>", "<span class=\"number\">",
"<@op>", "<span class=\"operator\">",
"<@type>", "<span class=\"type\">",
"<@name>", "<span class=\"name\">",
"<@keyword>", "<span class=\"keyword\">",
"</@comment>", "</span>",
"</@preprocessor>", "</span>",
"</@string>", "</span>",
"</@char>", "</span>",
"</@number>", "</span>",
"</@op>", "</span>",
"</@type>", "</span>",
"</@name>", "</span>",
"</@keyword>", "</span>",
html.reserve(src.size());
static const QLatin1String spanTags[] = {
QLatin1String("comment>"), QLatin1String("<span class=\"comment\">"),
QLatin1String("preprocessor>"), QLatin1String("<span class=\"preprocessor\">"),
QLatin1String("string>"), QLatin1String("<span class=\"string\">"),
QLatin1String("char>"), QLatin1String("<span class=\"char\">"),
QLatin1String("number>"), QLatin1String("<span class=\"number\">"),
QLatin1String("op>"), QLatin1String("<span class=\"operator\">"),
QLatin1String("type>"), QLatin1String("<span class=\"type\">"),
QLatin1String("name>"), QLatin1String("<span class=\"name\">"),
QLatin1String("keyword>"), QLatin1String("<span class=\"keyword\">")
};
int nTags = 9;
// Update the upper bound of k in the following code to match the length
// of the above array.
for (int i = 0, n = src.size(); i < n;) {
if (src.at(i) == charLangle) {
bool handled = false;
for (int k = 0; k != 18; ++k) {
const QString & tag = spanTags[2 * k];
if (i + tag.length() <= src.length() &&
tag == QStringRef(&src, i, tag.length())) {
html += spanTags[2 * k + 1];
i += tag.length();
handled = true;
break;
if (src.at(i) == QLatin1Char('<')) {
if (src.at(i + 1) == QLatin1Char('@')) {
i += 2;
bool handled = false;
for (int k = 0; k != nTags; ++k) {
const QLatin1String& tag = spanTags[2 * k];
if (i + tag.size() <= src.length() &&
tag == QStringRef(&src, i, tag.size())) {
html += spanTags[2 * k + 1];
i += tag.size();
handled = true;
break;
}
}
}
if (!handled) {
++i;
if (src.at(i) == charAt ||
(src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) {
if (!handled) {
// drop 'our' unknown tags (the ones still containing '@')
while (i < n && src.at(i) != QLatin1Char('>'))
++i;
++i;
}
else {
// retain all others
html += charLangle;
continue;
}
else if (src.at(i + 1) == QLatin1Char('/') && src.at(i + 2) == QLatin1Char('@')) {
i += 3;
bool handled = false;
for (int k = 0; k != nTags; ++k) {
const QLatin1String& tag = spanTags[2 * k];
if (i + tag.size() <= src.length() &&
tag == QStringRef(&src, i, tag.size())) {
html += QLatin1String("</span>");
i += tag.size();
handled = true;
break;
}
}
if (!handled) {
// drop 'our' unknown tags (the ones still containing '@')
while (i < n && src.at(i) != QLatin1Char('>'))
++i;
++i;
}
continue;
}
}
else {
html += src.at(i);
++i;
}
html += src.at(i);
++i;
}
return html;
}
@ -3655,7 +3631,7 @@ QString HtmlGenerator::protect(const QString &string, const QString &outputEncod
APPEND("&gt;");
} else if (ch == QLatin1Char('"')) {
APPEND("&quot;");
} else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F)
} else if ((outputEncoding == QLatin1String("ISO-8859-1") && ch.unicode() > 0x007F)
|| (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/'))
|| (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) {
// we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator
@ -3684,10 +3660,10 @@ QString HtmlGenerator::fileBase(const Node *node) const
if (!node->isAggregate()) {
switch (node->status()) {
case Node::Compat:
result += "-compat";
result += QLatin1String("-compat");
break;
case Node::Obsolete:
result += "-obsolete";
result += QLatin1String("-obsolete");
break;
default:
;
@ -4423,7 +4399,7 @@ void HtmlGenerator::generateManifestFile(const QString &manifest, const QString
QString fileName = manifest +"-manifest.xml";
QFile file(outputDir() + QLatin1Char('/') + fileName);
bool demos = false;
if (manifest == "demos")
if (manifest == QLatin1String("demos"))
demos = true;
bool proceed = false;

View File

@ -38,7 +38,7 @@
#ifndef HTMLGENERATOR_H
#define HTMLGENERATOR_H
#include <qmap.h>
#include <qhash.h>
#include <qregexp.h>
#include <qxmlstream.h>
#include "codemarker.h"
@ -187,7 +187,6 @@ private:
void generateQmlInstantiates(QmlTypeNode* qcn, CodeMarker* marker);
void generateInstantiatedBy(ClassNode* cn, CodeMarker* marker);
void generateRequisitesTable(const QStringList& requisitesOrder, QMap<QString, Text>& requisites);
void generateSection(const NodeList& nl,
const Node *relative,
CodeMarker *marker,
@ -232,7 +231,7 @@ private:
void writeDitaRefs(const DitaRefList& ditarefs);
QXmlStreamWriter& xmlWriter();
QMap<QString, QString> refMap;
QHash<QString, QString> refMap;
int codeIndent;
HelpProjectWriter *helpProjectWriter;
bool inObsoleteLink;

View File

@ -39,6 +39,8 @@
QT_BEGIN_NAMESPACE
QHash<QString,QString> Quoter::commentHash;
static void replaceMultipleNewlines(QString &s)
{
const int n = s.size();
@ -120,14 +122,16 @@ Quoter::Quoter()
* .html, .qrc, .ui, .xq, .xml .dita files:
<!-- [<id>] -->
*/
commentHash["pro"] = "#!";
commentHash["py"] = "#!";
commentHash["html"] = "<!--";
commentHash["qrc"] = "<!--";
commentHash["ui"] = "<!--";
commentHash["xml"] = "<!--";
commentHash["dita"] = "<!--";
commentHash["xq"] = "<!--";
if (!commentHash.size()) {
commentHash["pro"] = "#!";
commentHash["py"] = "#!";
commentHash["html"] = "<!--";
commentHash["qrc"] = "<!--";
commentHash["ui"] = "<!--";
commentHash["xml"] = "<!--";
commentHash["dita"] = "<!--";
commentHash["xq"] = "<!--";
}
}
void Quoter::reset()

View File

@ -78,7 +78,7 @@ private:
QStringList plainLines;
QStringList markedLines;
Location codeLocation;
QHash<QString,QString> commentHash;
static QHash<QString,QString> commentHash;
};
QT_END_NAMESPACE