From 13cd62a6f00c6c7b659c15e2462d43513b4b531d Mon Sep 17 00:00:00 2001 From: Tobe O Date: Mon, 9 Oct 2017 09:39:14 -0400 Subject: [PATCH] Perf update --- lib/src/router.dart | 11 ++++++----- lib/string_util.dart | 43 +++++++++++++++++++++++++++++++++++++++++ pubspec.yaml | 2 +- test/strip_test.dart | 46 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 lib/string_util.dart create mode 100644 test/strip_test.dart diff --git a/lib/src/router.dart b/lib/src/router.dart index bafbbae5..dfa1e42a 100644 --- a/lib/src/router.dart +++ b/lib/src/router.dart @@ -2,6 +2,7 @@ library angel_route.src.router; import 'extensible.dart'; import 'routing_exception.dart'; +import '../string_util.dart'; part 'symlink_route.dart'; part 'route.dart'; part 'routing_result.dart'; @@ -266,8 +267,8 @@ class Router { /// with the given method. RoutingResult resolve(String absolute, String relative, {String method: 'GET'}) { - final cleanAbsolute = absolute.replaceAll(_straySlashes, ''); - final cleanRelative = relative.replaceAll(_straySlashes, ''); + final cleanAbsolute = stripStraySlashes(absolute); + final cleanRelative = stripStraySlashes(relative); final segments = cleanRelative.split('/').where((str) => str.isNotEmpty); //print( // 'Now resolving $method "/$cleanRelative", absolute: $cleanAbsolute'); @@ -283,9 +284,9 @@ class Router { if (match != null) { final cleaned = s.join('/').replaceFirst(match[0], ''); - final tail = cleanRelative - .replaceAll(route._head, '') - .replaceAll(_straySlashes, ''); + var tail = cleanRelative + .replaceAll(route._head, ''); + tail = stripStraySlashes(tail); if (cleaned.isEmpty) { //print( diff --git a/lib/string_util.dart b/lib/string_util.dart new file mode 100644 index 00000000..9a9e5bf7 --- /dev/null +++ b/lib/string_util.dart @@ -0,0 +1,43 @@ +/// Helper functions to performantly transform strings, without `RegExp`. +library angel_route.string_util; + +/// Removes leading and trailing occurrences of a pattern from a string. +String stripStray(String haystack, String needle) { + int firstSlash; + + if (haystack.startsWith(needle)) { + firstSlash = haystack.indexOf(needle); + if (firstSlash == -1) return haystack; + } else { + firstSlash = -1; + } + + if (firstSlash == haystack.length - 1) + return haystack.length == 1 ? '' : haystack.substring(0, firstSlash); + + // Find last leading index of slash + for (int i = firstSlash + 1; i < haystack.length; i++) { + if (haystack[i] != needle) { + var sub = haystack.substring(i); + + if (!sub.endsWith(needle)) + return sub; + + var lastSlash = sub.lastIndexOf(needle); + + for (int j = lastSlash - 1; j >= 0; j--) { + if (sub[j] != needle) { + return sub.substring(0, j + 1); + } + } + + return lastSlash == -1 ? sub : sub.substring(0, lastSlash); + } + } + + return haystack.substring(0, firstSlash); +} + +String stripStraySlashes(String str) => stripStray(str, '/'); + +String stripRegexStraySlashes(String str) => stripStray(str, '\\/'); diff --git a/pubspec.yaml b/pubspec.yaml index b1ed6dac..c5aceb5f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: angel_route description: A powerful, isomorphic routing library for Dart. -version: 1.0.6 +version: 1.0.7 author: Tobe O homepage: https://github.com/angel-dart/angel_route dev_dependencies: diff --git a/test/strip_test.dart b/test/strip_test.dart new file mode 100644 index 00000000..955f1bf5 --- /dev/null +++ b/test/strip_test.dart @@ -0,0 +1,46 @@ +import 'package:angel_route/string_util.dart'; +import 'package:test/test.dart'; + +main() { + test('strip leading', () { + var a = '///a'; + var b = stripStraySlashes(a); + print('$a => $b'); + expect(b, 'a'); + }); + + test('strip trailing', () { + var a = 'a///'; + var b = stripStraySlashes(a); + print('$a => $b'); + expect(b, 'a'); + }); + + test('strip both', () { + var a = '///a///'; + var b = stripStraySlashes(a); + print('$a => $b'); + expect(b, 'a'); + }); + + test('intermediate slashes preserved', () { + var a = '///a///b//'; + var b = stripStraySlashes(a); + print('$a => $b'); + expect(b, 'a///b'); + }); + + test('only if starts with', () { + var a = 'd///a///b//'; + var b = stripStraySlashes(a); + print('$a => $b'); + expect(b, 'd///a///b'); + }); + + test('only if ends with', () { + var a = '///a///b//c'; + var b = stripStraySlashes(a); + print('$a => $b'); + expect(b, 'a///b//c'); + }); +} \ No newline at end of file