Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2184)

Unified Diff: runtime/lib/string_patch.dart

Issue 864463002: Create string efficiently from Uint16List/View. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add tests for external typed-data Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/lib/string.cc ('k') | runtime/vm/bootstrap_natives.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/lib/string_patch.dart
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index f22b6e1fe834d727301712c211dee90b1da25a22..76950644b18fcd51c9e1b457cd1c1f1a0b68eb97 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -2,10 +2,18 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+const int _maxAscii = 0x7f;
+const int _maxLatin1 = 0xff;
+const int _maxUtf16 = 0xffff;
+const int _maxUnicode = 0x10ffff;
+
patch class String {
/* patch */ factory String.fromCharCodes(Iterable<int> charCodes,
[int start = 0, int end]) {
- return _StringBase.createFromCharCodes(charCodes, start, end);
+ if (charCodes is! Iterable) throw new ArgumentError.value(charCodes, "charCodes");
+ if (start is! int) throw new ArgumentError.value(start, "start");
+ if (end != null && end is! int) throw new ArgumentError.value(end, "end");
+ return _StringBase.createFromCharCodes(charCodes, start, end, null);
}
/* patch */ factory String.fromCharCode(int charCode) {
@@ -80,11 +88,19 @@ class _StringBase {
int get hashCode native "String_getHashCode";
/**
- * Create the most efficient string representation for specified
- * [codePoints].
+ * Create the most efficient string representation for specified
+ * [charCodes].
+ *
+ * Only uses the character codes betwen index [start] and index [end] of
+ * `charCodes`. They must satisfy `0 <= start <= end <= charCodes.length`.
+ *
+ * The [limit] is an upper limit on the character codes in the iterable.
+ * It's `null` if unknown.
*/
static String createFromCharCodes(Iterable<int> charCodes,
- int start, int end) {
+ int start, int end,
+ int limit) {
+ if (start == null) throw new ArgumentError.notNull("start");
if (charCodes == null) throw new ArgumentError(charCodes);
// TODO(srdjan): Also skip copying of wide typed arrays.
final ccid = ClassID.getID(charCodes);
@@ -93,68 +109,102 @@ class _StringBase {
(ccid != ClassID.cidGrowableObjectArray) &&
(ccid != ClassID.cidImmutableArray)) {
if (charCodes is Uint8List) {
- isOneByteString = true;
- } else {
- // Treat charCodes as Iterable.
- if (start < 0) throw new RangeError.range(start, 0, charCodes.length);
- if (end != null && end < start) {
- throw new RangeError.range(end, start, charCodes.length);
- }
- var it = charCodes.iterator;
- for (int i = 0; i < start; i++) {
- if (!it.moveNext()) {
- throw new RangeError.range(start, 0, i);
- }
- }
- int bits = 0; // Bitwise or of all char codes in list.
- var list = [];
- if (end == null) {
- while (it.moveNext()) {
- int code = it.current;
- bits |= code;
- list.add(code);
- }
- } else {
- for (int i = start; i < end; i++) {
- if (!it.moveNext()) {
- throw new RangeError.range(end, start, i);
- }
- int code = it.current;
- bits |= code;
- list.add(code);
- }
- }
- charCodes = list;
- isOneByteString = (bits >= 0 && bits <= 0xff);
- start = 0;
- end = list.length;
+ end = RangeError.checkValidRange(start, end, charCodes.length);
+ return _createOneByteString(charCodes, start, end - start);
+ } else if (charCodes is! Uint16List) {
+ return _createStringFromIterable(charCodes, start, end);
}
}
int codeCount = charCodes.length;
- if (start < 0 || start > codeCount) {
- throw new RangeError.range(start, 0, codeCount);
+ end = RangeError.checkValidRange(start, end, codeCount);
+ final len = end - start;
+ if (len == 0) return "";
+ if (limit == null) {
+ limit = _scanCodeUnits(charCodes, start, end);
}
- if (end == null) {
- end = codeCount;
- } else if (end < start || end > codeCount) {
- throw new RangeError.range(end, start, codeCount);
+ if (limit < 0) {
+ throw new ArgumentError(charCodes);
}
- final len = end - start;
- if (!isOneByteString) {
- for (int i = start; i < end; i++) {
- int e = charCodes[i];
- if (e is! _Smi) throw new ArgumentError(e);
- // Is e Latin1?
- if ((e < 0) || (e > 0xFF)) {
- return _createFromCodePoints(charCodes, start, end);
+ if (limit <= _maxLatin1) {
+ return _createOneByteString(charCodes, start, len);
+ }
+ if (limit <= _maxUtf16) {
+ return _TwoByteString._allocateFromTwoByteList(charCodes, start, end);
+ }
+ // TODO(lrn): Consider passing limit to _createFromCodePoints, because
+ // the function is currently fully generic and doesn't know that its
+ // charCodes are not all Latin-1 or Utf-16.
+ return _createFromCodePoints(charCodes, start, end);
+ }
+
+ static int _scanCodeUnits(List<int> charCodes, int start, int end) {
+ int bits = 0;
+ for (int i = start; i < end; i++) {
+ int code = charCodes[i];
+ if (code is! _Smi) throw new ArgumentError(charCodes);
+ bits |= code;
+ }
+ return bits;
+ }
+
+ static String _createStringFromIterable(Iterable<int> charCodes,
+ int start, int end) {
+ // Treat charCodes as Iterable.
+ if (charCodes is EfficientLength) {
+ int length = charCodes.length;
+ end = RangeError.checkValidRange(start, end, length);
+ List charCodeList = new List.from(charCodes.take(end).skip(start),
+ growable: false);
+ return createFromCharCodes(charCodeList, 0, charCodeList.length, null);
+ }
+ // Don't know length of iterable, so iterate and see if all the values
+ // are there.
+ if (start < 0) throw new RangeError.range(start, 0, charCodes.length);
+ var it = charCodes.iterator;
+ for (int i = 0; i < start; i++) {
+ if (!it.moveNext()) {
+ throw new RangeError.range(start, 0, i);
+ }
+ }
+ List charCodeList;
+ int bits = 0; // Bitwise-or of all char codes in list.
+ if (end == null) {
+ var list = [];
+ while (it.moveNext()) {
+ int code = it.current;
+ bits |= code;
+ list.add(code);
+ }
+ charCodeList = makeListFixedLength(list);
+ } else {
+ if (end < start) {
+ throw new RangeError.range(end, start, charCodes.length);
+ }
+ int len = end - start;
+ var list = new List(len);
+ for (int i = 0; i < len; i++) {
+ if (!it.moveNext()) {
+ throw new RangeError.range(end, start, start + i);
}
+ int code = it.current;
+ bits |= code;
+ list[i] = code;
}
+ charCodeList = list;
}
- // Allocate a one byte string. When the list is 128 entries or longer,
- // it's faster to perform a runtime-call.
- if (len >= 128) {
- return _OneByteString._allocateFromOneByteList(charCodes, start, end);
+ int length = charCodeList.length;
+ if (bits < 0) {
+ throw new ArgumentError(charCodes);
}
+ bool isOneByteString = (bits <= _maxLatin1);
+ if (isOneByteString) {
+ return _createOneByteString(charCodeList, 0, length);
+ }
+ return createFromCharCodes(charCodeList, 0, length, bits);
+ }
+
+ static String _createOneByteString(List<int> charCodes, int start, int len) {
+ // It's always faster to do this in Dart than to call into the runtime.
var s = _OneByteString._allocate(len);
for (int i = 0; i < len; i++) {
s._setAt(i, charCodes[start + i]);
@@ -162,6 +212,12 @@ class _StringBase {
return s;
}
+ static String _createTwoByteString(List<int> charCodes, int start, int len) {
+ // TODO(lrn): Create string without scanning charCodes again - all values
+ // in the [start..end] range are uint16 values.
+ return _createFromCodePoints(charCodes, start, end);
+ }
+
static String _createFromCodePoints(List<int> codePoints, int start, int end)
native "StringBase_createFromCodePoints";
@@ -1140,6 +1196,9 @@ class _TwoByteString extends _StringBase implements String {
"_TwoByteString can only be allocated by the VM");
}
+ static String _allocateFromTwoByteList(List list, int start, int end)
+ native "TwoByteString_allocateFromTwoByteList";
+
bool _isWhitespace(int codeUnit) {
return _StringBase._isTwoByteWhitespace(codeUnit);
}
« no previous file with comments | « runtime/lib/string.cc ('k') | runtime/vm/bootstrap_natives.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698