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

Side by Side 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, 10 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/lib/string.cc ('k') | runtime/vm/bootstrap_natives.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 const int _maxAscii = 0x7f;
6 const int _maxLatin1 = 0xff;
7 const int _maxUtf16 = 0xffff;
8 const int _maxUnicode = 0x10ffff;
9
5 patch class String { 10 patch class String {
6 /* patch */ factory String.fromCharCodes(Iterable<int> charCodes, 11 /* patch */ factory String.fromCharCodes(Iterable<int> charCodes,
7 [int start = 0, int end]) { 12 [int start = 0, int end]) {
8 return _StringBase.createFromCharCodes(charCodes, start, end); 13 if (charCodes is! Iterable) throw new ArgumentError.value(charCodes, "charCo des");
14 if (start is! int) throw new ArgumentError.value(start, "start");
15 if (end != null && end is! int) throw new ArgumentError.value(end, "end");
16 return _StringBase.createFromCharCodes(charCodes, start, end, null);
9 } 17 }
10 18
11 /* patch */ factory String.fromCharCode(int charCode) { 19 /* patch */ factory String.fromCharCode(int charCode) {
12 if (charCode >= 0) { 20 if (charCode >= 0) {
13 if (charCode <= 0xff) { 21 if (charCode <= 0xff) {
14 return _OneByteString._allocate(1).._setAt(0, charCode); 22 return _OneByteString._allocate(1).._setAt(0, charCode);
15 } 23 }
16 if (charCode <= 0xffff) { 24 if (charCode <= 0xffff) {
17 return _StringBase._createFromCodePoints(new _List(1)..[0] = charCode, 25 return _StringBase._createFromCodePoints(new _List(1)..[0] = charCode,
18 0, 1); 26 0, 1);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 factory _StringBase._uninstantiable() { 81 factory _StringBase._uninstantiable() {
74 throw new UnsupportedError( 82 throw new UnsupportedError(
75 "_StringBase can't be instaniated"); 83 "_StringBase can't be instaniated");
76 } 84 }
77 85
78 Type get runtimeType => String; 86 Type get runtimeType => String;
79 87
80 int get hashCode native "String_getHashCode"; 88 int get hashCode native "String_getHashCode";
81 89
82 /** 90 /**
83 * Create the most efficient string representation for specified 91 * Create the most efficient string representation for specified
84 * [codePoints]. 92 * [charCodes].
93 *
94 * Only uses the character codes betwen index [start] and index [end] of
95 * `charCodes`. They must satisfy `0 <= start <= end <= charCodes.length`.
96 *
97 * The [limit] is an upper limit on the character codes in the iterable.
98 * It's `null` if unknown.
85 */ 99 */
86 static String createFromCharCodes(Iterable<int> charCodes, 100 static String createFromCharCodes(Iterable<int> charCodes,
87 int start, int end) { 101 int start, int end,
102 int limit) {
103 if (start == null) throw new ArgumentError.notNull("start");
88 if (charCodes == null) throw new ArgumentError(charCodes); 104 if (charCodes == null) throw new ArgumentError(charCodes);
89 // TODO(srdjan): Also skip copying of wide typed arrays. 105 // TODO(srdjan): Also skip copying of wide typed arrays.
90 final ccid = ClassID.getID(charCodes); 106 final ccid = ClassID.getID(charCodes);
91 bool isOneByteString = false; 107 bool isOneByteString = false;
92 if ((ccid != ClassID.cidArray) && 108 if ((ccid != ClassID.cidArray) &&
93 (ccid != ClassID.cidGrowableObjectArray) && 109 (ccid != ClassID.cidGrowableObjectArray) &&
94 (ccid != ClassID.cidImmutableArray)) { 110 (ccid != ClassID.cidImmutableArray)) {
95 if (charCodes is Uint8List) { 111 if (charCodes is Uint8List) {
96 isOneByteString = true; 112 end = RangeError.checkValidRange(start, end, charCodes.length);
97 } else { 113 return _createOneByteString(charCodes, start, end - start);
98 // Treat charCodes as Iterable. 114 } else if (charCodes is! Uint16List) {
99 if (start < 0) throw new RangeError.range(start, 0, charCodes.length); 115 return _createStringFromIterable(charCodes, start, end);
100 if (end != null && end < start) {
101 throw new RangeError.range(end, start, charCodes.length);
102 }
103 var it = charCodes.iterator;
104 for (int i = 0; i < start; i++) {
105 if (!it.moveNext()) {
106 throw new RangeError.range(start, 0, i);
107 }
108 }
109 int bits = 0; // Bitwise or of all char codes in list.
110 var list = [];
111 if (end == null) {
112 while (it.moveNext()) {
113 int code = it.current;
114 bits |= code;
115 list.add(code);
116 }
117 } else {
118 for (int i = start; i < end; i++) {
119 if (!it.moveNext()) {
120 throw new RangeError.range(end, start, i);
121 }
122 int code = it.current;
123 bits |= code;
124 list.add(code);
125 }
126 }
127 charCodes = list;
128 isOneByteString = (bits >= 0 && bits <= 0xff);
129 start = 0;
130 end = list.length;
131 } 116 }
132 } 117 }
133 int codeCount = charCodes.length; 118 int codeCount = charCodes.length;
134 if (start < 0 || start > codeCount) { 119 end = RangeError.checkValidRange(start, end, codeCount);
135 throw new RangeError.range(start, 0, codeCount); 120 final len = end - start;
121 if (len == 0) return "";
122 if (limit == null) {
123 limit = _scanCodeUnits(charCodes, start, end);
136 } 124 }
137 if (end == null) { 125 if (limit < 0) {
138 end = codeCount; 126 throw new ArgumentError(charCodes);
139 } else if (end < start || end > codeCount) {
140 throw new RangeError.range(end, start, codeCount);
141 } 127 }
142 final len = end - start; 128 if (limit <= _maxLatin1) {
143 if (!isOneByteString) { 129 return _createOneByteString(charCodes, start, len);
144 for (int i = start; i < end; i++) { 130 }
145 int e = charCodes[i]; 131 if (limit <= _maxUtf16) {
146 if (e is! _Smi) throw new ArgumentError(e); 132 return _TwoByteString._allocateFromTwoByteList(charCodes, start, end);
147 // Is e Latin1? 133 }
148 if ((e < 0) || (e > 0xFF)) { 134 // TODO(lrn): Consider passing limit to _createFromCodePoints, because
149 return _createFromCodePoints(charCodes, start, end); 135 // the function is currently fully generic and doesn't know that its
150 } 136 // charCodes are not all Latin-1 or Utf-16.
137 return _createFromCodePoints(charCodes, start, end);
138 }
139
140 static int _scanCodeUnits(List<int> charCodes, int start, int end) {
141 int bits = 0;
142 for (int i = start; i < end; i++) {
143 int code = charCodes[i];
144 if (code is! _Smi) throw new ArgumentError(charCodes);
145 bits |= code;
146 }
147 return bits;
148 }
149
150 static String _createStringFromIterable(Iterable<int> charCodes,
151 int start, int end) {
152 // Treat charCodes as Iterable.
153 if (charCodes is EfficientLength) {
154 int length = charCodes.length;
155 end = RangeError.checkValidRange(start, end, length);
156 List charCodeList = new List.from(charCodes.take(end).skip(start),
157 growable: false);
158 return createFromCharCodes(charCodeList, 0, charCodeList.length, null);
159 }
160 // Don't know length of iterable, so iterate and see if all the values
161 // are there.
162 if (start < 0) throw new RangeError.range(start, 0, charCodes.length);
163 var it = charCodes.iterator;
164 for (int i = 0; i < start; i++) {
165 if (!it.moveNext()) {
166 throw new RangeError.range(start, 0, i);
151 } 167 }
152 } 168 }
153 // Allocate a one byte string. When the list is 128 entries or longer, 169 List charCodeList;
154 // it's faster to perform a runtime-call. 170 int bits = 0; // Bitwise-or of all char codes in list.
155 if (len >= 128) { 171 if (end == null) {
156 return _OneByteString._allocateFromOneByteList(charCodes, start, end); 172 var list = [];
173 while (it.moveNext()) {
174 int code = it.current;
175 bits |= code;
176 list.add(code);
177 }
178 charCodeList = makeListFixedLength(list);
179 } else {
180 if (end < start) {
181 throw new RangeError.range(end, start, charCodes.length);
182 }
183 int len = end - start;
184 var list = new List(len);
185 for (int i = 0; i < len; i++) {
186 if (!it.moveNext()) {
187 throw new RangeError.range(end, start, start + i);
188 }
189 int code = it.current;
190 bits |= code;
191 list[i] = code;
192 }
193 charCodeList = list;
157 } 194 }
195 int length = charCodeList.length;
196 if (bits < 0) {
197 throw new ArgumentError(charCodes);
198 }
199 bool isOneByteString = (bits <= _maxLatin1);
200 if (isOneByteString) {
201 return _createOneByteString(charCodeList, 0, length);
202 }
203 return createFromCharCodes(charCodeList, 0, length, bits);
204 }
205
206 static String _createOneByteString(List<int> charCodes, int start, int len) {
207 // It's always faster to do this in Dart than to call into the runtime.
158 var s = _OneByteString._allocate(len); 208 var s = _OneByteString._allocate(len);
159 for (int i = 0; i < len; i++) { 209 for (int i = 0; i < len; i++) {
160 s._setAt(i, charCodes[start + i]); 210 s._setAt(i, charCodes[start + i]);
161 } 211 }
162 return s; 212 return s;
163 } 213 }
164 214
215 static String _createTwoByteString(List<int> charCodes, int start, int len) {
216 // TODO(lrn): Create string without scanning charCodes again - all values
217 // in the [start..end] range are uint16 values.
218 return _createFromCodePoints(charCodes, start, end);
219 }
220
165 static String _createFromCodePoints(List<int> codePoints, int start, int end) 221 static String _createFromCodePoints(List<int> codePoints, int start, int end)
166 native "StringBase_createFromCodePoints"; 222 native "StringBase_createFromCodePoints";
167 223
168 String operator [](int index) native "String_charAt"; 224 String operator [](int index) native "String_charAt";
169 225
170 int codeUnitAt(int index) native "String_codeUnitAt"; 226 int codeUnitAt(int index) native "String_codeUnitAt";
171 227
172 int get length native "String_getLength"; 228 int get length native "String_getLength";
173 229
174 bool get isEmpty { 230 bool get isEmpty {
(...skipping 958 matching lines...) Expand 10 before | Expand all | Expand 10 after
1133 void _setAt(int index, int codePoint) native "OneByteString_setAt"; 1189 void _setAt(int index, int codePoint) native "OneByteString_setAt";
1134 } 1190 }
1135 1191
1136 1192
1137 class _TwoByteString extends _StringBase implements String { 1193 class _TwoByteString extends _StringBase implements String {
1138 factory _TwoByteString._uninstantiable() { 1194 factory _TwoByteString._uninstantiable() {
1139 throw new UnsupportedError( 1195 throw new UnsupportedError(
1140 "_TwoByteString can only be allocated by the VM"); 1196 "_TwoByteString can only be allocated by the VM");
1141 } 1197 }
1142 1198
1199 static String _allocateFromTwoByteList(List list, int start, int end)
1200 native "TwoByteString_allocateFromTwoByteList";
1201
1143 bool _isWhitespace(int codeUnit) { 1202 bool _isWhitespace(int codeUnit) {
1144 return _StringBase._isTwoByteWhitespace(codeUnit); 1203 return _StringBase._isTwoByteWhitespace(codeUnit);
1145 } 1204 }
1146 1205
1147 bool operator ==(Object other) { 1206 bool operator ==(Object other) {
1148 return super == other; 1207 return super == other;
1149 } 1208 }
1150 } 1209 }
1151 1210
1152 1211
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1219 class _CodeUnits extends Object with ListMixin<int>, 1278 class _CodeUnits extends Object with ListMixin<int>,
1220 UnmodifiableListMixin<int> { 1279 UnmodifiableListMixin<int> {
1221 /** The string that this is the code units of. */ 1280 /** The string that this is the code units of. */
1222 String _string; 1281 String _string;
1223 1282
1224 _CodeUnits(this._string); 1283 _CodeUnits(this._string);
1225 1284
1226 int get length => _string.length; 1285 int get length => _string.length;
1227 int operator[](int i) => _string.codeUnitAt(i); 1286 int operator[](int i) => _string.codeUnitAt(i);
1228 } 1287 }
OLDNEW
« 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