Skip to content

Commit

Permalink
🐛 fix optimization regressions introduced in #6 (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
techouse authored Apr 14, 2024
1 parent 5b16b59 commit 656431b
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 60 deletions.
110 changes: 50 additions & 60 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:collection' show SplayTreeMap;
import 'dart:convert' show latin1, utf8, Encoding;
import 'dart:math' show min;
import 'dart:typed_data' show ByteBuffer;

import 'package:collection/collection.dart' show MapEquality;
Expand Down Expand Up @@ -150,46 +151,40 @@ final class Utils {
static String escape(String str, {Format? format = Format.rfc3986}) {
final StringBuffer buffer = StringBuffer();

for (int j = 0; j < str.length; j += _segmentLimit) {
final String segment = str.length >= _segmentLimit
? str.substring(j, j + _segmentLimit)
: str;

for (int i = 0; i < segment.length; ++i) {
final int c = segment.codeUnitAt(i);

/// These 69 characters are safe for escaping
/// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./
if ((c >= 0x30 && c <= 0x39) || // 0-9
(c >= 0x41 && c <= 0x5A) || // A-Z
(c >= 0x61 && c <= 0x7A) || // a-z
c == 0x40 || // @
c == 0x2A || // *
c == 0x5F || // _
c == 0x2D || // -
c == 0x2B || // +
c == 0x2E || // .
c == 0x2F || // /
(format == Format.rfc1738 && (c == 0x28 || c == 0x29))) {
buffer.write(segment[i]);
continue;
}

if (c < 256) {
buffer.writeAll([
'%',
c.toRadixString(16).padLeft(2, '0').toUpperCase(),
]);
continue;
}
for (int i = 0; i < str.length; ++i) {
final int c = str.codeUnitAt(i);

/// These 69 characters are safe for escaping
/// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./
if ((c >= 0x30 && c <= 0x39) || // 0-9
(c >= 0x41 && c <= 0x5A) || // A-Z
(c >= 0x61 && c <= 0x7A) || // a-z
c == 0x40 || // @
c == 0x2A || // *
c == 0x5F || // _
c == 0x2D || // -
c == 0x2B || // +
c == 0x2E || // .
c == 0x2F || // /
(format == Format.rfc1738 && (c == 0x28 || c == 0x29))) {
buffer.write(str[i]);
continue;
}

buffer.writeAll(
[
'%u',
c.toRadixString(16).padLeft(4, '0').toUpperCase(),
],
);
if (c < 256) {
buffer.writeAll([
'%',
c.toRadixString(16).padLeft(2, '0').toUpperCase(),
]);
continue;
}

buffer.writeAll(
[
'%u',
c.toRadixString(16).padLeft(4, '0').toUpperCase(),
],
);
}

return buffer.toString();
Expand All @@ -202,34 +197,29 @@ final class Utils {
@Deprecated('Use Uri.decodeComponent instead')
static String unescape(String str) {
final StringBuffer buffer = StringBuffer();
for (int j = 0; j < str.length; j += _segmentLimit) {
final String segment = str.length >= _segmentLimit
? str.substring(j, j + _segmentLimit)
: str.substring(j);
int i = 0;

while (i < segment.length) {
final int c = segment.codeUnitAt(i);

if (c == 0x25) {
if (segment[i + 1] == 'u') {
buffer.writeCharCode(
int.parse(segment.substring(i + 2, i + 6), radix: 16),
);
i += 6;
continue;
}
int i = 0;

while (i < str.length) {
final int c = str.codeUnitAt(i);

if (c == 0x25) {
if (str[i + 1] == 'u') {
buffer.writeCharCode(
int.parse(segment.substring(i + 1, i + 3), radix: 16),
int.parse(str.substring(i + 2, i + 6), radix: 16),
);
i += 3;
i += 6;
continue;
}

buffer.write(segment[i]);
i++;
buffer.writeCharCode(
int.parse(str.substring(i + 1, i + 3), radix: 16),
);
i += 3;
continue;
}

buffer.write(str[i]);
i++;
}

return buffer.toString();
Expand Down Expand Up @@ -271,7 +261,7 @@ final class Utils {

for (int j = 0; j < str!.length; j += _segmentLimit) {
final String segment = str.length >= _segmentLimit
? str.substring(j, j + _segmentLimit)
? str.substring(j, min(j + _segmentLimit, str.length))
: str;

for (int i = 0; i < segment.length; ++i) {
Expand Down
15 changes: 15 additions & 0 deletions test/unit/utils_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ void main() {
);
});

test('encode huge string', () {
final String hugeString = 'a' * 1000000;
expect(Utils.encode(hugeString), equals(hugeString));
});

test('decode', () {
expect(Utils.decode('foo%2Bbar'), equals('foo+bar'));
// exceptions
Expand Down Expand Up @@ -143,6 +148,11 @@ void main() {
);
});

test('escape huge string', () {
final String hugeString = 'äöü' * 1000000;
expect(Utils.escape(hugeString), equals('%E4%F6%FC' * 1000000));
});

test('unescape', () {
expect(Utils.unescape('abc123'), equals('abc123'));
expect(Utils.unescape('%E4%F6%FC'), equals('äöü'));
Expand All @@ -164,6 +174,11 @@ void main() {
);
});

test('unescape huge string', () {
final String hugeString = '%E4%F6%FC' * 1000000;
expect(Utils.unescape(hugeString), equals('äöü' * 1000000));
});

group('merge', () {
test('merges SplayTreeMap with List', () {
expect(
Expand Down

0 comments on commit 656431b

Please sign in to comment.