Optimise decode/encodeURI
authorLars Knoll <lars.knoll@digia.com>
Wed, 30 Jan 2013 08:44:15 +0000 (09:44 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Wed, 30 Jan 2013 13:07:50 +0000 (14:07 +0100)
The code contained some needless creation of temporary
QStrings, that were taking up ~50% of the time spent in
these methods.

Change-Id: Iba494e5e92c08a0056d6eb6a947d080209aa7ce5
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/v4/qv4globalobject.cpp

index 74cd32d..70ae41c 100644 (file)
@@ -147,8 +147,9 @@ static QString unescape(const QString &input)
     return result;
 }
 
-static const char uriReserved[] = ";/?:@&=+$,";
-static const char uriUnescaped[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()";
+static const char uriReserved[] = ";/?:@&=+$,#";
+static const char uriUnescaped[] = "-_.!~*'()";
+static const char uriUnescapedReserved[] = "-_.!~*'();/?:@&=+$,#";
 
 static void addEscapeSequence(QString &output, uchar ch)
 {
@@ -157,7 +158,7 @@ static void addEscapeSequence(QString &output, uchar ch)
     output.append(QLatin1Char(toHex(ch & 0xf)));
 }
 
-static QString encode(const QString &input, const QString &unescapedSet, bool *ok)
+static QString encode(const QString &input, const char *unescapedSet, bool *ok)
 {
     *ok = true;
     QString output;
@@ -165,7 +166,22 @@ static QString encode(const QString &input, const QString &unescapedSet, bool *o
     int i = 0;
     while (i < length) {
         const QChar c = input.at(i);
-        if (!unescapedSet.contains(c)) {
+        bool escape = true;
+        if ((c.unicode() >= 'a' && c.unicode() <= 'z') ||
+            (c.unicode() >= 'A' && c.unicode() <= 'Z') ||
+            (c.unicode() >= '0' && c.unicode() <= '9')) {
+            escape = false;
+        } else {
+            const char *r = unescapedSet;
+            while (*r) {
+                if (*r == c.unicode()) {
+                    escape = false;
+                    break;
+                }
+                ++r;
+            }
+        }
+        if (escape) {
             uint uc = c.unicode();
             if ((uc >= 0xDC00) && (uc <= 0xDFFF)) {
                 *ok = false;
@@ -211,10 +227,16 @@ static QString encode(const QString &input, const QString &unescapedSet, bool *o
     return output;
 }
 
-static QString decode(const QString &input, const QString &reservedSet, bool *ok)
+enum DecodeMode {
+    DecodeAll,
+    DecodeNonReserved
+};
+
+static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
 {
     *ok = true;
     QString output;
+    output.reserve(input.length());
     const int length = input.length();
     int i = 0;
     const QChar percent = QLatin1Char('%');
@@ -287,11 +309,19 @@ static QString decode(const QString &input, const QString &reservedSet, bool *ok
                     output.append(QChar(l));
                 }
             } else {
-                QChar z(b);
-                if (!reservedSet.contains(z)) {
-                    output.append(z);
+                if (decodeMode == DecodeNonReserved && b <= 0x40) {
+                    const char *r = uriReserved;
+                    while (*r) {
+                        if (*r == b)
+                            break;
+                        ++r;
+                    }
+                    if (*r)
+                        output.append(input.mid(start, i - start + 1));
+                    else
+                        output.append(QChar(b));
                 } else {
-                    output.append(input.mid(start, i - start + 1));
+                    output.append(QChar(b));
                 }
             }
         } else {
@@ -599,7 +629,7 @@ Value GlobalFunctions::method_decodeURI(ExecutionContext *parentCtx, Value, Valu
 
     QString uriString = argv[0].toString(parentCtx)->toQString();
     bool ok;
-    QString out = decode(uriString, QString::fromUtf8(uriReserved) + QString::fromUtf8("#"), &ok);
+    QString out = decode(uriString, DecodeNonReserved, &ok);
     if (!ok)
         parentCtx->throwURIError(Value::fromString(parentCtx, QStringLiteral("malformed URI sequence")));
 
@@ -614,7 +644,7 @@ Value GlobalFunctions::method_decodeURIComponent(ExecutionContext *parentCtx, Va
 
     QString uriString = argv[0].toString(parentCtx)->toQString();
     bool ok;
-    QString out = decode(uriString, QString(), &ok);
+    QString out = decode(uriString, DecodeAll, &ok);
     if (!ok)
         parentCtx->throwURIError(Value::fromString(parentCtx, QStringLiteral("malformed URI sequence")));
 
@@ -629,7 +659,7 @@ Value GlobalFunctions::method_encodeURI(ExecutionContext *parentCtx, Value, Valu
 
     QString uriString = argv[0].toString(parentCtx)->toQString();
     bool ok;
-    QString out = encode(uriString, QLatin1String(uriReserved) + QLatin1String(uriUnescaped) + QString::fromUtf8("#"), &ok);
+    QString out = encode(uriString, uriUnescapedReserved, &ok);
     if (!ok)
         parentCtx->throwURIError(Value::fromString(parentCtx, QStringLiteral("malformed URI sequence")));
 
@@ -644,7 +674,7 @@ Value GlobalFunctions::method_encodeURIComponent(ExecutionContext *parentCtx, Va
 
     QString uriString = argv[0].toString(parentCtx)->toQString();
     bool ok;
-    QString out = encode(uriString, QString(uriUnescaped), &ok);
+    QString out = encode(uriString, uriUnescaped, &ok);
     if (!ok)
         parentCtx->throwURIError(Value::fromString(parentCtx, QStringLiteral("malformed URI sequence")));