[convert] Use s.substring(start, end) directly and relax identical() check on wasm
diff --git a/pkgs/convert/lib/src/string_replacer.dart b/pkgs/convert/lib/src/string_replacer.dart index 0c45f66..1c7c95d 100644 --- a/pkgs/convert/lib/src/string_replacer.dart +++ b/pkgs/convert/lib/src/string_replacer.dart
@@ -113,7 +113,7 @@ ]) { end = RangeError.checkValidRange(start, end, input.length); if (replacements.isEmpty) { - return _substring(input, start, end); + return input.substring(start, end); } if (_isWeb || end - start < 64 || replacements.length == 1) { return _replaceOneShotIndexOf(input, replacements, start, end); @@ -135,7 +135,7 @@ @override String convert(String input, [int start = 0, int? end]) { end = RangeError.checkValidRange(start, end, input.length); - return _substring(input, start, end); + return input.substring(start, end); } @override @@ -177,7 +177,7 @@ i++; } if (i == end) { - return _substring(input, start, end); + return input.substring(start, end); } final out = StringBuffer(); @@ -235,7 +235,7 @@ i++; } if (i == end) { - return _substring(input, start, end); + return input.substring(start, end); } StringBuffer? out; @@ -259,7 +259,7 @@ } if (out == null) { - return _substring(input, start, end); + return input.substring(start, end); } if (end > lastFlush) { out.write(input.substring(lastFlush, end)); @@ -409,7 +409,7 @@ } if (activeKeys == null) { - return _substring(s, start, end); + return s.substring(start, end); } return _finishActiveKeyReplace( @@ -463,7 +463,7 @@ } if (activeKeys == null) { - return _substring(s, start, end); + return s.substring(start, end); } return _finishActiveKeyReplace( @@ -478,12 +478,6 @@ ); } -/// Returns [s] unchanged when the slice covers the entire string, avoiding a -/// `JSStringImpl` wrapper allocation on `dart2wasm` where -/// `substring(0, length)` does not return `this`. -String _substring(String s, int start, int end) => - (start == 0 && end == s.length) ? s : s.substring(start, end); - /// Repeatedly emits the earliest (and longest on ties) match among /// [activeKeys], lazily advancing `positions[k]` via `s.indexOf` only for keys /// whose cached match position fell behind `lastFlush`, and dropping keys from
diff --git a/pkgs/convert/test/string_replacer_test.dart b/pkgs/convert/test/string_replacer_test.dart index 49af7c8..4fe2dde 100644 --- a/pkgs/convert/test/string_replacer_test.dart +++ b/pkgs/convert/test/string_replacer_test.dart
@@ -6,6 +6,17 @@ import 'package:convert/convert.dart'; import 'package:test/test.dart'; +// On dart2wasm, JSStringImpl.substring(0, length) allocates a new Wasm struct +// wrapper around the JS externref rather than returning `this`. +const _isWasm = bool.fromEnvironment('dart.tool.dart2wasm'); + +void _expectSameString(String actual, String expected) { + expect(actual, expected); + if (!_isWasm) { + expect(identical(actual, expected), isTrue); + } +} + void main() { group('StringReplacer', () { test('rejects empty key in constructor and static replace', () { @@ -28,8 +39,8 @@ test('empty map returns identical input', () { final replacer = StringReplacer(const {}); final input = String.fromCharCodes('hello'.codeUnits); - expect(identical(replacer.convert(input), input), isTrue); - expect(identical(StringReplacer.replace(input, const {}), input), isTrue); + _expectSameString(replacer.convert(input), input); + _expectSameString(StringReplacer.replace(input, const {}), input); expect(replacer.convert(input, 1, 4), 'ell'); expect(StringReplacer.replace(input, const {}, 1, 4), 'ell'); }); @@ -46,17 +57,17 @@ final multiReplacer = StringReplacer({'az': 'Y', 'bc': 'Z'}); final input = String.fromCharCodes('abd_efg'.codeUnits); - expect(identical(singleReplacer.convert(input), input), isTrue); - expect( - identical(StringReplacer.replace(input, {'x': 'y', 'z': 'w'}), input), - isTrue, + _expectSameString(singleReplacer.convert(input), input); + _expectSameString( + StringReplacer.replace(input, {'x': 'y', 'z': 'w'}), + input, ); // Note: 'a' and 'b' appear in `input`, so the first-unit table bucket is // non-null, but neither 'az' nor 'bc' matches. Must still return `input`. - expect(identical(multiReplacer.convert(input), input), isTrue); - expect( - identical(StringReplacer.replace(input, {'az': 'Y', 'bc': 'Z'}), input), - isTrue, + _expectSameString(multiReplacer.convert(input), input); + _expectSameString( + StringReplacer.replace(input, {'az': 'Y', 'bc': 'Z'}), + input, ); }); @@ -186,8 +197,8 @@ final replacer = StringReplacer(map); final padding = '.' * 80; final noMatch = String.fromCharCodes('${padding}baz$padding'.codeUnits); - expect(identical(replacer.convert(noMatch), noMatch), isTrue); - expect(identical(StringReplacer.replace(noMatch, map), noMatch), isTrue); + _expectSameString(replacer.convert(noMatch), noMatch); + _expectSameString(StringReplacer.replace(noMatch, map), noMatch); final oneMatch = '${padding}foo$padding'; final expectedOne = '${padding}bar$padding'; @@ -253,8 +264,8 @@ // 1. 0 active keys in long string -> identical return final none = String.fromCharCodes('$pad.$pad.$pad'.codeUnits); - expect(identical(replacer.convert(none), none), isTrue); - expect(identical(StringReplacer.replace(none, map), none), isTrue); + _expectSameString(replacer.convert(none), none); + _expectSameString(StringReplacer.replace(none, map), none); expect(replacer.convert(none, 10, none.length - 10), none.substring(10, none.length - 10)); expect(StringReplacer.replace(none, map, 10, none.length - 10),