common: Make frequently called util methods more efficient
authorManuel Nickschas <sputnick@quassel-irc.org>
Sun, 3 Sep 2017 23:04:25 +0000 (01:04 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sun, 3 Sep 2017 23:20:52 +0000 (01:20 +0200)
Remove unnecessary temporary allocations and string copies in the
various methods in util.*, and avoid calling API functions that do
more than we need them to do in favor of an efficient implementation.

Ensure that frequently used QRegExp instances are created statically
and reused between invocations, so they can make use of JIT and other
optimizations.

As some of the affected methods are called *very* frequently, this
provides significant savings in terms of allocations, and
significantly reduces memory fragmentation as well.

Modernize some of the related code. Clean up includes, too.

src/common/quassel.cpp
src/common/util.cpp
src/common/util.h
src/qtui/qtuistyle.cpp
src/uisupport/actioncollection.cpp

index f498ae7..2e1e46a 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <QCoreApplication>
 #include <QDateTime>
+#include <QDir>
 #include <QFileInfo>
 #include <QHostAddress>
 #include <QLibraryInfo>
index 8b1139e..695ca4a 100644 (file)
 
 #include "util.h"
 
+#include <algorithm>
+#include <array>
+#include <utility>
+
 #include <QCoreApplication>
+#include <QDateTime>
 #include <QDebug>
-#include <QFile>
 #include <QTextCodec>
+#include <QVector>
 
 #include "quassel.h"
 
-class QMetaMethod;
-
 // MIBenum values from http://www.iana.org/assignments/character-sets/character-sets.xml#table-character-sets-1
 static QList<int> utf8DetectionBlacklist = QList<int>()
     << 39 /* ISO-2022-JP */;
 
-QString nickFromMask(QString mask)
+QString nickFromMask(const QString &mask)
 {
-    return mask.section('!', 0, 0);
+    return mask.left(mask.indexOf('!'));
 }
 
 
-QString userFromMask(QString mask)
+QString userFromMask(const QString &mask)
 {
-    QString userhost = mask.section('!', 1);
-    if (userhost.isEmpty()) return QString();
-    return userhost.section('@', 0, 0);
+    const int offset = mask.indexOf('!') + 1;
+    if (offset <= 0)
+        return {};
+    const int length = mask.indexOf('@', offset) - offset;
+    return mask.mid(offset, length >= 0 ? length : -1);
 }
 
 
-QString hostFromMask(QString mask)
+QString hostFromMask(const QString &mask)
 {
-    QString userhost = mask.section('!', 1);
-    if (userhost.isEmpty()) return QString();
-    return userhost.section('@', 1);
+    const int excl = mask.indexOf('!');
+    if (excl < 0)
+        return {};
+    const int offset = mask.indexOf('@', excl + 1) + 1;
+    return offset > 0 && offset < mask.size() ? mask.mid(offset) : QString{};
 }
 
 
-bool isChannelName(QString str)
+bool isChannelName(const QString &str)
 {
-    return QString("#&!+").contains(str[0]);
+    static constexpr std::array<QChar, 4> prefixes{{'#', '&', '!', '+'}};
+    return std::any_of(prefixes.cbegin(), prefixes.cend(), [&str](QChar c) { return c == str[0]; });
 }
 
 
-QString stripFormatCodes(QString str)
+QString stripFormatCodes(QString message)
 {
-    str.remove(QRegExp("\x03(\\d\\d?(,\\d\\d?)?)?"));
-    str.remove('\x02');
-    str.remove('\x0f');
-    str.remove('\x12');
-    str.remove('\x16');
-    str.remove('\x1d');
-    str.remove('\x1f');
-    return str;
+    static QRegExp regEx{"\x03(\\d\\d?(,\\d\\d?)?)?|[\x02\x0f\x12\x16\x1d\x1f]"};
+    return message.remove(regEx);
 }
 
 
@@ -165,12 +167,13 @@ uint editingDistance(const QString &s1, const QString &s2)
 
 QString secondsToString(int timeInSeconds)
 {
-    QList<QPair<int, QString> > timeUnit;
-    timeUnit.append(qMakePair(365*24*60*60, QCoreApplication::translate("Quassel::secondsToString()", "year")));
-    timeUnit.append(qMakePair(24*60*60, QCoreApplication::translate("Quassel::secondsToString()", "day")));
-    timeUnit.append(qMakePair(60*60, QCoreApplication::translate("Quassel::secondsToString()", "h")));
-    timeUnit.append(qMakePair(60, QCoreApplication::translate("Quassel::secondsToString()", "min")));
-    timeUnit.append(qMakePair(1, QCoreApplication::translate("Quassel::secondsToString()", "sec")));
+    static QVector<std::pair<int, QString>> timeUnit {
+        std::make_pair(365*24*60*60, QCoreApplication::translate("Quassel::secondsToString()", "year")),
+        std::make_pair(24*60*60, QCoreApplication::translate("Quassel::secondsToString()", "day")),
+        std::make_pair(60*60, QCoreApplication::translate("Quassel::secondsToString()", "h")),
+        std::make_pair(60, QCoreApplication::translate("Quassel::secondsToString()", "min")),
+        std::make_pair(1, QCoreApplication::translate("Quassel::secondsToString()", "sec"))
+    };
 
     if (timeInSeconds != 0) {
         QStringList returnString;
index 92c9a5f..61530a0 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef UTIL_H
-#define UTIL_H
+#pragma once
 
-#include <QDir>
-#include <QVariant>
+#include <QList>
 #include <QString>
-#include <QMetaMethod>
-#include <QDateTime>
+#include <QVariant>
 
-// TODO Use versions from Network instead
-QString nickFromMask(QString mask);
-QString userFromMask(QString mask);
-QString hostFromMask(QString mask);
-bool isChannelName(QString str);
+QString nickFromMask(const QString &mask);
+QString userFromMask(const QString &mask);
+QString hostFromMask(const QString &mask);
+bool isChannelName(const QString &str);
 
 //! Strip mIRC format codes
 QString stripFormatCodes(QString);
@@ -83,5 +79,3 @@ QByteArray prettyDigest(const QByteArray &digest);
  * @return String with current date/time substituted in via formatting codes
  */
 QString formatCurrentDateTimeInString(const QString &formatStr);
-
-#endif
index 9dc997f..d167b2e 100644 (file)
@@ -22,6 +22,7 @@
 #include "qtuistyle.h"
 
 #include <QFile>
+#include <QFileInfo>
 #include <QTextStream>
 
 QtUiStyle::QtUiStyle(QObject *parent) : UiStyle(parent)
index 2c53777..6715388 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <QAction>
 #include <QDebug>
+#include <QMetaMethod>
 
 #include "actioncollection.h"