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

Side by Side Diff: lib/string_patch.dart

Issue 13097009: - Consolidate String sources in the runtime libraries. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: Created 7 years, 9 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 | « lib/string_base.dart ('k') | no next file » | 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 patch class String { 5 patch class String {
6 /* patch */ factory String.fromCharCodes(Iterable<int> charCodes) { 6 /* patch */ factory String.fromCharCodes(Iterable<int> charCodes) {
7 return _StringBase.createFromCharCodes(charCodes); 7 return _StringBase.createFromCharCodes(charCodes);
8 } 8 }
9 } 9 }
10
11
12 /**
13 * [_StringBase] contains common methods used by concrete String
14 * implementations, e.g., _OneByteString.
15 */
16 class _StringBase {
17
18 factory _StringBase._uninstantiable() {
19 throw new UnsupportedError(
20 "_StringBase can't be instaniated");
21 }
22
23 int get hashCode native "String_getHashCode";
24
25 /**
26 * Create the most efficient string representation for specified
27 * [codePoints].
28 */
29 static String createFromCharCodes(Iterable<int> charCodes) {
30 if (charCodes is! _ObjectArray && charCodes is! _GrowableObjectArray) {
31 charCodes = new List<int>.from(charCodes, growable: false);
32 }
33 return _createFromCodePoints(charCodes);
34 }
35
36 static String _createFromCodePoints(List<int> codePoints)
37 native "StringBase_createFromCodePoints";
38
39 String operator [](int index) native "String_charAt";
40
41 int codeUnitAt(int index) native "String_codeUnitAt";
42
43 int get length native "String_getLength";
44
45 bool get isEmpty {
46 return this.length == 0;
47 }
48
49 String operator +(String other) native "String_concat";
50
51 String concat(String other) => this + other;
52
53 String toString() {
54 return this;
55 }
56
57 bool operator ==(Object other) {
58 if (identical(this, other)) {
59 return true;
60 }
61 if ((other is !String) ||
62 (this.length != other.length)) {
63 // TODO(5413632): Compare hash codes when both are present.
64 return false;
65 }
66 return this.compareTo(other) == 0;
67 }
68
69 int compareTo(String other) {
70 int thisLength = this.length;
71 int otherLength = other.length;
72 int len = (thisLength < otherLength) ? thisLength : otherLength;
73 for (int i = 0; i < len; i++) {
74 int thisCodePoint = this.codeUnitAt(i);
75 int otherCodePoint = other.codeUnitAt(i);
76 if (thisCodePoint < otherCodePoint) {
77 return -1;
78 }
79 if (thisCodePoint > otherCodePoint) {
80 return 1;
81 }
82 }
83 if (thisLength < otherLength) return -1;
84 if (thisLength > otherLength) return 1;
85 return 0;
86 }
87
88 bool _substringMatches(int start, String other) {
89 if (other.isEmpty) return true;
90 if ((start < 0) || (start >= this.length)) {
91 return false;
92 }
93 final int len = other.length;
94 if ((start + len) > this.length) {
95 return false;
96 }
97 for (int i = 0; i < len; i++) {
98 if (this.codeUnitAt(i + start) != other.codeUnitAt(i)) {
99 return false;
100 }
101 }
102 return true;
103 }
104
105 bool endsWith(String other) {
106 return _substringMatches(this.length - other.length, other);
107 }
108
109 bool startsWith(String other) {
110 return _substringMatches(0, other);
111 }
112
113 int indexOf(String other, [int start = 0]) {
114 if (other.isEmpty) {
115 return start < this.length ? start : this.length;
116 }
117 if ((start < 0) || (start >= this.length)) {
118 return -1;
119 }
120 int len = this.length - other.length + 1;
121 for (int index = start; index < len; index++) {
122 if (_substringMatches(index, other)) {
123 return index;
124 }
125 }
126 return -1;
127 }
128
129 int lastIndexOf(String other, [int start = null]) {
130 if (start == null) start = length - 1;
131 if (other.isEmpty) {
132 return min(this.length, start);
133 }
134 if (start >= this.length) {
135 start = this.length - 1;
136 }
137 for (int index = start; index >= 0; index--) {
138 if (_substringMatches(index, other)) {
139 return index;
140 }
141 }
142 return -1;
143 }
144
145 String substring(int startIndex, [int endIndex]) {
146 if (endIndex == null) endIndex = this.length;
147
148 if ((startIndex < 0) || (startIndex > this.length)) {
149 throw new RangeError.value(startIndex);
150 }
151 if ((endIndex < 0) || (endIndex > this.length)) {
152 throw new RangeError.value(endIndex);
153 }
154 if (startIndex > endIndex) {
155 throw new RangeError.value(startIndex);
156 }
157 return _substringUnchecked(startIndex, endIndex);
158 }
159
160 String slice([int startIndex, int endIndex]) {
161 int start, end;
162 if (startIndex == null) {
163 start = 0;
164 } else if (startIndex is! int) {
165 throw new ArgumentError("startIndex is not int");
166 } else if (startIndex >= 0) {
167 start = startIndex;
168 } else {
169 start = this.length + startIndex;
170 }
171 if (start < 0 || start > this.length) {
172 throw new RangeError(
173 "startIndex out of range: $startIndex (length: $length)");
174 }
175 if (endIndex == null) {
176 end = this.length;
177 } else if (endIndex is! int) {
178 throw new ArgumentError("endIndex is not int");
179 } else if (endIndex >= 0) {
180 end = endIndex;
181 } else {
182 end = this.length + endIndex;
183 }
184 if (end < 0 || end > this.length) {
185 throw new RangeError(
186 "endIndex out of range: $endIndex (length: $length)");
187 }
188 if (end < start) {
189 throw new ArgumentError(
190 "End before start: $endIndex < $startIndex (length: $length)");
191 }
192 return _substringUnchecked(start, end);
193 }
194
195 String _substringUnchecked(int startIndex, int endIndex) {
196 assert(endIndex != null);
197 assert((startIndex >= 0) && (startIndex <= this.length));
198 assert((endIndex >= 0) && (endIndex <= this.length));
199 assert(startIndex <= endIndex);
200
201 if (startIndex == endIndex) {
202 return "";
203 }
204 if ((startIndex + 1) == endIndex) {
205 return this[startIndex];
206 }
207 return _substringUncheckedNative(startIndex, endIndex);
208 }
209
210 String _substringUncheckedNative(int startIndex, int endIndex)
211 native "StringBase_substringUnchecked";
212
213 String trim() {
214 final int len = this.length;
215 int first = 0;
216 for (; first < len; first++) {
217 if (!_isWhitespace(this.codeUnitAt(first))) {
218 break;
219 }
220 }
221 if (len == first) {
222 // String contains only whitespaces.
223 return "";
224 }
225 int last = len - 1;
226 for (; last >= first; last--) {
227 if (!_isWhitespace(this.codeUnitAt(last))) {
228 break;
229 }
230 }
231 if ((first == 0) && (last == (len - 1))) {
232 // Returns this string if it does not have leading or trailing
233 // whitespaces.
234 return this;
235 } else {
236 return _substringUnchecked(first, last + 1);
237 }
238 }
239
240 bool contains(Pattern pattern, [int startIndex = 0]) {
241 if (pattern is String) {
242 return indexOf(pattern, startIndex) >= 0;
243 }
244 return pattern.allMatches(this.substring(startIndex)).iterator.moveNext();
245 }
246
247 String replaceFirst(Pattern pattern, String replacement) {
248 if (pattern is! Pattern) {
249 throw new ArgumentError("${pattern} is not a Pattern");
250 }
251 if (replacement is! String) {
252 throw new ArgumentError("${replacement} is not a String");
253 }
254 StringBuffer buffer = new StringBuffer();
255 int startIndex = 0;
256 Iterator iterator = pattern.allMatches(this).iterator;
257 if (iterator.moveNext()) {
258 Match match = iterator.current;
259 buffer..write(this.substring(startIndex, match.start))
260 ..write(replacement);
261 startIndex = match.end;
262 }
263 return (buffer..write(this.substring(startIndex))).toString();
264 }
265
266 String replaceAll(Pattern pattern, String replacement) {
267 if (pattern is! Pattern) {
268 throw new ArgumentError("${pattern} is not a Pattern");
269 }
270 if (replacement is! String) {
271 throw new ArgumentError(
272 "${replacement} is not a String or Match->String function");
273 }
274 StringBuffer buffer = new StringBuffer();
275 int startIndex = 0;
276 for (Match match in pattern.allMatches(this)) {
277 buffer..write(this.substring(startIndex, match.start))
278 ..write(replacement);
279 startIndex = match.end;
280 }
281 return (buffer..write(this.substring(startIndex))).toString();
282 }
283
284 String replaceAllMapped(Pattern pattern, String replace(Match match)) {
285 return splitMapJoin(pattern, onMatch: replace);
286 }
287
288 static String _matchString(Match match) => match[0];
289 static String _stringIdentity(String string) => string;
290
291 String _splitMapJoinEmptyString(String onMatch(Match match),
292 String onNonMatch(String nonMatch)) {
293 // Pattern is the empty string.
294 StringBuffer buffer = new StringBuffer();
295 int length = this.length;
296 int i = 0;
297 buffer.write(onNonMatch(""));
298 while (i < length) {
299 buffer.write(onMatch(new _StringMatch(i, this, "")));
300 // Special case to avoid splitting a surrogate pair.
301 int code = this.codeUnitAt(i);
302 if ((code & ~0x3FF) == 0xD800 && length > i + 1) {
303 // Leading surrogate;
304 code = this.codeUnitAt(i + 1);
305 if ((code & ~0x3FF) == 0xDC00) {
306 // Matching trailing surrogate.
307 buffer.write(onNonMatch(this.substring(i, i + 2)));
308 i += 2;
309 continue;
310 }
311 }
312 buffer.write(onNonMatch(this[i]));
313 i++;
314 }
315 buffer.write(onMatch(new _StringMatch(i, this, "")));
316 buffer.write(onNonMatch(""));
317 return buffer.toString();
318 }
319
320 String splitMapJoin(Pattern pattern,
321 {String onMatch(Match match),
322 String onNonMatch(String nonMatch)}) {
323 if (pattern is! Pattern) {
324 throw new ArgumentError("${pattern} is not a Pattern");
325 }
326 if (onMatch == null) onMatch = _matchString;
327 if (onNonMatch == null) onNonMatch = _stringIdentity;
328 if (pattern is String) {
329 String stringPattern = pattern;
330 if (stringPattern.isEmpty) {
331 return _splitMapJoinEmptyString(onMatch, onNonMatch);
332 }
333 }
334 StringBuffer buffer = new StringBuffer();
335 int startIndex = 0;
336 for (Match match in pattern.allMatches(this)) {
337 buffer.write(onNonMatch(this.substring(startIndex, match.start)));
338 buffer.write(onMatch(match).toString());
339 startIndex = match.end;
340 }
341 buffer.write(onNonMatch(this.substring(startIndex)));
342 return buffer.toString();
343 }
344
345
346 /**
347 * Convert all objects in [values] to strings and concat them
348 * into a result string.
349 */
350 static String _interpolate(List values) {
351 int numValues = values.length;
352 var stringList = new List(numValues);
353 for (int i = 0; i < numValues; i++) {
354 stringList[i] = values[i].toString();
355 }
356 return _concatAll(stringList);
357 }
358
359 Iterable<Match> allMatches(String str) {
360 List<Match> result = new List<Match>();
361 int length = str.length;
362 int patternLength = this.length;
363 int startIndex = 0;
364 while (true) {
365 int position = str.indexOf(this, startIndex);
366 if (position == -1) {
367 break;
368 }
369 result.add(new _StringMatch(position, str, this));
370 int endIndex = position + patternLength;
371 if (endIndex == length) {
372 break;
373 } else if (position == endIndex) {
374 ++startIndex; // empty match, advance and restart
375 } else {
376 startIndex = endIndex;
377 }
378 }
379 return result;
380 }
381
382 List<String> split(Pattern pattern) {
383 if ((pattern is String) && pattern.isEmpty) {
384 List<String> result = new List<String>(length);
385 for (int i = 0; i < length; i++) {
386 result[i] = this[i];
387 }
388 return result;
389 }
390 int length = this.length;
391 Iterator iterator = pattern.allMatches(this).iterator;
392 if (length == 0 && iterator.moveNext()) {
393 // A matched empty string input returns the empty list.
394 return <String>[];
395 }
396 List<String> result = new List<String>();
397 int startIndex = 0;
398 int previousIndex = 0;
399 while (true) {
400 if (startIndex == length || !iterator.moveNext()) {
401 result.add(this._substringUnchecked(previousIndex, length));
402 break;
403 }
404 Match match = iterator.current;
405 if (match.start == length) {
406 result.add(this._substringUnchecked(previousIndex, length));
407 break;
408 }
409 int endIndex = match.end;
410 if (startIndex == endIndex && endIndex == previousIndex) {
411 ++startIndex; // empty match, advance and restart
412 continue;
413 }
414 result.add(this._substringUnchecked(previousIndex, match.start));
415 startIndex = previousIndex = endIndex;
416 }
417 return result;
418 }
419
420 List<int> get codeUnits => new CodeUnits(this);
421
422 Runes get runes => new Runes(this);
423
424 String toUpperCase() native "String_toUpperCase";
425
426 String toLowerCase() native "String_toLowerCase";
427
428 // Implementations of Strings methods follow below.
429 static String join(Iterable<String> strings, String separator) {
430 bool first = true;
431 List<String> stringsList = <String>[];
432 for (String string in strings) {
433 if (first) {
434 first = false;
435 } else {
436 stringsList.add(separator);
437 }
438
439 if (string is! String) {
440 throw new ArgumentError(Error.safeToString(string));
441 }
442 stringsList.add(string);
443 }
444 return concatAll(stringsList);
445 }
446
447 static String concatAll(Iterable<String> strings) {
448 _ObjectArray stringsArray;
449 if (strings is _ObjectArray) {
450 stringsArray = strings;
451 for (int i = 0; i < strings.length; i++) {
452 if (strings[i] is! String) throw new ArgumentError(strings[i]);
453 }
454 } else {
455 int len = strings.length;
456 stringsArray = new _ObjectArray(len);
457 int i = 0;
458 for (String string in strings) {
459 if (string is! String) throw new ArgumentError(string);
460 stringsArray[i++] = string;
461 }
462 }
463 return _concatAll(stringsArray);
464 }
465
466 static String _concatAll(List<String> strings)
467 native "Strings_concatAll";
468 }
469
470
471 class _OneByteString extends _StringBase implements String {
472 factory _OneByteString._uninstantiable() {
473 throw new UnsupportedError(
474 "_OneByteString can only be allocated by the VM");
475 }
476
477 int get hashCode native "String_getHashCode";
478
479 // Checks for one-byte whitespaces only.
480 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
481 // whitespaces for one byte strings.
482 bool _isWhitespace(int codePoint) {
483 return
484 (codePoint == 32) || // Space.
485 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
486 }
487
488 String _substringUncheckedNative(int startIndex, int endIndex)
489 native "OneByteString_substringUnchecked";
490
491 List<String> _splitWithCharCode(int charCode)
492 native "OneByteString_splitWithCharCode";
493
494 List<String> split(Pattern pattern) {
495 if ((pattern is _OneByteString) && (pattern.length == 1)) {
496 return _splitWithCharCode(pattern.codeUnitAt(0));
497 }
498 return super.split(pattern);
499 }
500 }
501
502
503 class _TwoByteString extends _StringBase implements String {
504 factory _TwoByteString._uninstantiable() {
505 throw new UnsupportedError(
506 "_TwoByteString can only be allocated by the VM");
507 }
508
509 // Checks for one-byte whitespaces only.
510 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
511 // whitespaces. Add checking for multi-byte whitespace codepoints.
512 bool _isWhitespace(int codePoint) {
513 return
514 (codePoint == 32) || // Space.
515 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
516 }
517 }
518
519
520 class _FourByteString extends _StringBase implements String {
521 factory _FourByteString._uninstantiable() {
522 throw new UnsupportedError(
523 "_FourByteString can only be allocated by the VM");
524 }
525
526 // Checks for one-byte whitespaces only.
527 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
528 // whitespaces. Add checking for multi-byte whitespace codepoints.
529 bool _isWhitespace(int codePoint) {
530 return
531 (codePoint == 32) || // Space.
532 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
533 }
534 }
535
536
537 class _ExternalOneByteString extends _StringBase implements String {
538 factory _ExternalOneByteString._uninstantiable() {
539 throw new UnsupportedError(
540 "_ExternalOneByteString can only be allocated by the VM");
541 }
542
543 // Checks for one-byte whitespaces only.
544 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
545 // whitespaces for one byte strings.
546 bool _isWhitespace(int codePoint) {
547 return
548 (codePoint == 32) || // Space.
549 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
550 }
551 }
552
553
554 class _ExternalTwoByteString extends _StringBase implements String {
555 factory _ExternalTwoByteString._uninstantiable() {
556 throw new UnsupportedError(
557 "_ExternalTwoByteString can only be allocated by the VM");
558 }
559
560 // Checks for one-byte whitespaces only.
561 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
562 // whitespaces. Add checking for multi-byte whitespace codepoints.
563 bool _isWhitespace(int codePoint) {
564 return
565 (codePoint == 32) || // Space.
566 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
567 }
568 }
569
570
571 class _ExternalFourByteString extends _StringBase implements String {
572 factory _ExternalFourByteString._uninstantiable() {
573 throw new UnsupportedError(
574 "ExternalFourByteString can only be allocated by the VM");
575 }
576
577 // Checks for one-byte whitespaces only.
578 // TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
579 // whitespaces. Add checking for multi-byte whitespace codepoints.
580 bool _isWhitespace(int codePoint) {
581 return
582 (codePoint == 32) || // Space.
583 ((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
584 }
585 }
586
587
588 class _StringMatch implements Match {
589 const _StringMatch(int this.start,
590 String this.str,
591 String this.pattern);
592
593 int get end => start + pattern.length;
594 String operator[](int g) => group(g);
595 int get groupCount => 0;
596
597 String group(int group) {
598 if (group != 0) {
599 throw new RangeError.value(group);
600 }
601 return pattern;
602 }
603
604 List<String> groups(List<int> groups) {
605 List<String> result = new List<String>();
606 for (int g in groups) {
607 result.add(group(g));
608 }
609 return result;
610 }
611
612 final int start;
613 final String str;
614 final String pattern;
615 }
OLDNEW
« no previous file with comments | « lib/string_base.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698