Avoid unnecessary string and list copies

Change-Id: I78bc4d307be69ce3bbfaa3ca3dd7c85e654af8d6
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Yuri Vilmanis
2023-10-30 17:41:50 +10:30
parent 0a3bfc9323
commit 1acf00d3e1
4 changed files with 24 additions and 14 deletions

View File

@@ -38,7 +38,7 @@ QByteArray FastPreprocessor::run(Document::Ptr newDoc,
mergeEnvironment(i.key()); mergeEnvironment(i.key());
} }
const QList<Document::Include> includes = doc->resolvedIncludes(); const QList<Document::Include> &includes = doc->resolvedIncludes();
for (const Document::Include &i : includes) for (const Document::Include &i : includes)
mergeEnvironment(i.resolvedFileName()); mergeEnvironment(i.resolvedFileName());
@@ -69,7 +69,7 @@ void FastPreprocessor::mergeEnvironment(const FilePath &filePath)
{ {
if (Utils::insert(_merged, filePath)) { if (Utils::insert(_merged, filePath)) {
if (Document::Ptr doc = _snapshot.document(filePath)) { if (Document::Ptr doc = _snapshot.document(filePath)) {
const QList<Document::Include> includes = doc->resolvedIncludes(); const QList<Document::Include> &includes = doc->resolvedIncludes();
for (const Document::Include &i : includes) for (const Document::Include &i : includes)
mergeEnvironment(i.resolvedFileName()); mergeEnvironment(i.resolvedFileName());

View File

@@ -453,7 +453,7 @@ QStringView FilePath::host() const
QStringView FilePath::pathView() const QStringView FilePath::pathView() const
{ {
return QStringView(m_data).left(m_pathLen); return QStringView(m_data.constData(), m_pathLen);
} }
QString FilePath::path() const QString FilePath::path() const
@@ -469,7 +469,17 @@ void FilePath::setParts(const QStringView scheme, const QStringView host, QStrin
path = path.mid(3); path = path.mid(3);
m_hash = 0; m_hash = 0;
m_data = path.toString() + scheme.toString() + host.toString();
// The equivalent of:
// m_data = path.toString() + scheme.toString() + host.toString();
// but with less copying.
// Note: The QStringBuilder optimization does not currently work in this case.
m_data.resize(0);
m_data.reserve(m_schemeLen + m_hostLen + m_pathLen);
m_data.append(path);
m_data.append(scheme);
m_data.append(host);
m_schemeLen = scheme.size(); m_schemeLen = scheme.size();
m_hostLen = host.size(); m_hostLen = host.size();
m_pathLen = path.size(); m_pathLen = path.size();
@@ -1480,7 +1490,7 @@ FilePath FilePath::relativePathFrom(const FilePath &anchor) const
absoluteAnchorPath = anchor.absoluteFilePath(); absoluteAnchorPath = anchor.absoluteFilePath();
else else
return {}; return {};
QString relativeFilePath = calcRelativePath(absPath.path(), absoluteAnchorPath.path()); QString relativeFilePath = calcRelativePath(absPath.pathView(), absoluteAnchorPath.pathView());
if (!filename.isEmpty()) { if (!filename.isEmpty()) {
if (relativeFilePath == ".") if (relativeFilePath == ".")
relativeFilePath.clear(); relativeFilePath.clear();
@@ -1505,14 +1515,14 @@ FilePath FilePath::relativePathFrom(const FilePath &anchor) const
\see FilePath::isRelativePath(), FilePath::relativePathFrom(), FilePath::relativeChildPath() \see FilePath::isRelativePath(), FilePath::relativePathFrom(), FilePath::relativeChildPath()
*/ */
QString FilePath::calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath) QString FilePath::calcRelativePath(QStringView absolutePath, QStringView absoluteAnchorPath)
{ {
if (absolutePath.isEmpty() || absoluteAnchorPath.isEmpty()) if (absolutePath.isEmpty() || absoluteAnchorPath.isEmpty())
return QString(); return QString();
// TODO using split() instead of parsing the strings by char index is slow // TODO using split() instead of parsing the strings by char index is slow
// and needs more memory (but the easiest implementation for now) // and needs more memory (but the easiest implementation for now)
const QStringList splits1 = absolutePath.split('/'); const QList<QStringView> splits1 = absolutePath.split('/');
const QStringList splits2 = absoluteAnchorPath.split('/'); const QList<QStringView> splits2 = absoluteAnchorPath.split('/');
int i = 0; int i = 0;
while (i < splits1.count() && i < splits2.count() && splits1.at(i) == splits2.at(i)) while (i < splits1.count() && i < splits2.count() && splits1.at(i) == splits2.at(i))
++i; ++i;

View File

@@ -258,7 +258,7 @@ public:
[[nodiscard]] static int rootLength(const QStringView path); // Assumes no scheme and host [[nodiscard]] static int rootLength(const QStringView path); // Assumes no scheme and host
[[nodiscard]] static int schemeAndHostLength(const QStringView path); [[nodiscard]] static int schemeAndHostLength(const QStringView path);
static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath); static QString calcRelativePath(QStringView absolutePath, QStringView absoluteAnchorPath);
//! Returns a filepath the represents the same file on a local drive //! Returns a filepath the represents the same file on a local drive
expected_str<FilePath> localSource() const; expected_str<FilePath> localSource() const;

View File

@@ -46,11 +46,11 @@ PreprocessStackEntry::PreprocessStackEntry(PreprocessorSection s, bool p, bool c
class PreprocessContext { class PreprocessContext {
public: public:
PreprocessContext(); PreprocessContext();
bool process(const QString &in, QString *out, QString *errorMessage); bool process(QStringView in, QString *out, QString *errorMessage);
private: private:
void reset(); void reset();
PreprocessorSection preprocessorLine(const QString & in, QString *ifExpression) const; PreprocessorSection preprocessorLine(QStringView in, QString *ifExpression) const;
mutable QRegularExpression m_ifPattern; mutable QRegularExpression m_ifPattern;
mutable QRegularExpression m_elsifPattern; mutable QRegularExpression m_elsifPattern;
@@ -81,7 +81,7 @@ void PreprocessContext::reset()
// Determine type of line and return enumeration, cut out // Determine type of line and return enumeration, cut out
// expression for '@if/@elsif'. // expression for '@if/@elsif'.
PreprocessorSection PreprocessContext::preprocessorLine(const QString &in, PreprocessorSection PreprocessContext::preprocessorLine(QStringView in,
QString *ifExpression) const QString *ifExpression) const
{ {
QRegularExpressionMatch match = m_ifPattern.match(in); QRegularExpressionMatch match = m_ifPattern.match(in);
@@ -111,7 +111,7 @@ static inline QString msgEmptyStack(int line)
return QString::fromLatin1("Unmatched '@endif' at line %1.").arg(line); return QString::fromLatin1("Unmatched '@endif' at line %1.").arg(line);
} }
bool PreprocessContext::process(const QString &in, QString *out, QString *errorMessage) bool PreprocessContext::process(QStringView in, QString *out, QString *errorMessage)
{ {
out->clear(); out->clear();
if (in.isEmpty()) if (in.isEmpty())
@@ -121,7 +121,7 @@ bool PreprocessContext::process(const QString &in, QString *out, QString *errorM
reset(); reset();
const QChar newLine = QLatin1Char('\n'); const QChar newLine = QLatin1Char('\n');
const QStringList lines = in.split(newLine); const QList<QStringView> lines = in.split(newLine);
const int lineCount = lines.size(); const int lineCount = lines.size();
bool first = true; bool first = true;
for (int l = 0; l < lineCount; l++) { for (int l = 0; l < lineCount; l++) {