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

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

Powered by Google App Engine
This is Rietveld 408576698