Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 /** | 5 /** |
| 6 * [_StringBase] contains common methods used by concrete String | 6 * [_StringBase] contains common methods used by concrete String |
| 7 * implementations, e.g., _OneByteString. | 7 * implementations, e.g., _OneByteString. |
| 8 */ | 8 */ |
| 9 class _StringBase { | 9 class _StringBase { |
| 10 | 10 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 31 } | 31 } |
| 32 } | 32 } |
| 33 return _createFromCodePoints(objectArray); | 33 return _createFromCodePoints(objectArray); |
| 34 } | 34 } |
| 35 | 35 |
| 36 static String _createFromCodePoints(List<int> codePoints) | 36 static String _createFromCodePoints(List<int> codePoints) |
| 37 native "StringBase_createFromCodePoints"; | 37 native "StringBase_createFromCodePoints"; |
| 38 | 38 |
| 39 String operator [](int index) native "String_charAt"; | 39 String operator [](int index) native "String_charAt"; |
| 40 | 40 |
| 41 int charCodeAt(int index) native "String_charCodeAt"; | 41 int codeUnitAt(int index) native "String_codeUnitAt"; |
| 42 | |
| 43 int codeUnitAt(int index) { | |
| 44 return charCodeAt(index); | |
| 45 } | |
| 46 | 42 |
| 47 int get length native "String_getLength"; | 43 int get length native "String_getLength"; |
| 48 | 44 |
| 49 bool get isEmpty { | 45 bool get isEmpty { |
| 50 return this.length == 0; | 46 return this.length == 0; |
| 51 } | 47 } |
| 52 | 48 |
| 53 String concat(String other) native "String_concat"; | 49 String concat(String other) native "String_concat"; |
| 54 | 50 |
| 55 String toString() { | 51 String toString() { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 66 return false; | 62 return false; |
| 67 } | 63 } |
| 68 return this.compareTo(other) == 0; | 64 return this.compareTo(other) == 0; |
| 69 } | 65 } |
| 70 | 66 |
| 71 int compareTo(String other) { | 67 int compareTo(String other) { |
| 72 int thisLength = this.length; | 68 int thisLength = this.length; |
| 73 int otherLength = other.length; | 69 int otherLength = other.length; |
| 74 int len = (thisLength < otherLength) ? thisLength : otherLength; | 70 int len = (thisLength < otherLength) ? thisLength : otherLength; |
| 75 for (int i = 0; i < len; i++) { | 71 for (int i = 0; i < len; i++) { |
| 76 int thisCodePoint = this.charCodeAt(i); | 72 int thisCodePoint = this.codeUnitAt(i); |
| 77 int otherCodePoint = other.charCodeAt(i); | 73 int otherCodePoint = other.codeUnitAt(i); |
| 78 if (thisCodePoint < otherCodePoint) { | 74 if (thisCodePoint < otherCodePoint) { |
| 79 return -1; | 75 return -1; |
| 80 } | 76 } |
| 81 if (thisCodePoint > otherCodePoint) { | 77 if (thisCodePoint > otherCodePoint) { |
| 82 return 1; | 78 return 1; |
| 83 } | 79 } |
| 84 } | 80 } |
| 85 if (thisLength < otherLength) return -1; | 81 if (thisLength < otherLength) return -1; |
| 86 if (thisLength > otherLength) return 1; | 82 if (thisLength > otherLength) return 1; |
| 87 return 0; | 83 return 0; |
| 88 } | 84 } |
| 89 | 85 |
| 90 bool _substringMatches(int start, String other) { | 86 bool _substringMatches(int start, String other) { |
| 91 if (other.isEmpty) return true; | 87 if (other.isEmpty) return true; |
| 92 if ((start < 0) || (start >= this.length)) { | 88 if ((start < 0) || (start >= this.length)) { |
| 93 return false; | 89 return false; |
| 94 } | 90 } |
| 95 final int len = other.length; | 91 final int len = other.length; |
| 96 if ((start + len) > this.length) { | 92 if ((start + len) > this.length) { |
| 97 return false; | 93 return false; |
| 98 } | 94 } |
| 99 for (int i = 0; i < len; i++) { | 95 for (int i = 0; i < len; i++) { |
| 100 if (this.charCodeAt(i + start) != other.charCodeAt(i)) { | 96 if (this.codeUnitAt(i + start) != other.codeUnitAt(i)) { |
| 101 return false; | 97 return false; |
| 102 } | 98 } |
| 103 } | 99 } |
| 104 return true; | 100 return true; |
| 105 } | 101 } |
| 106 | 102 |
| 107 bool endsWith(String other) { | 103 bool endsWith(String other) { |
| 108 return _substringMatches(this.length - other.length, other); | 104 return _substringMatches(this.length - other.length, other); |
| 109 } | 105 } |
| 110 | 106 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 return _substringUncheckedNative(startIndex, endIndex); | 205 return _substringUncheckedNative(startIndex, endIndex); |
| 210 } | 206 } |
| 211 | 207 |
| 212 String _substringUncheckedNative(int startIndex, int endIndex) | 208 String _substringUncheckedNative(int startIndex, int endIndex) |
| 213 native "StringBase_substringUnchecked"; | 209 native "StringBase_substringUnchecked"; |
| 214 | 210 |
| 215 String trim() { | 211 String trim() { |
| 216 final int len = this.length; | 212 final int len = this.length; |
| 217 int first = 0; | 213 int first = 0; |
| 218 for (; first < len; first++) { | 214 for (; first < len; first++) { |
| 219 if (!_isWhitespace(this.charCodeAt(first))) { | 215 if (!_isWhitespace(this.codeUnitAt(first))) { |
| 220 break; | 216 break; |
| 221 } | 217 } |
| 222 } | 218 } |
| 223 if (len == first) { | 219 if (len == first) { |
| 224 // String contains only whitespaces. | 220 // String contains only whitespaces. |
| 225 return ""; | 221 return ""; |
| 226 } | 222 } |
| 227 int last = len - 1; | 223 int last = len - 1; |
| 228 for (; last >= first; last--) { | 224 for (; last >= first; last--) { |
| 229 if (!_isWhitespace(this.charCodeAt(last))) { | 225 if (!_isWhitespace(this.codeUnitAt(last))) { |
| 230 break; | 226 break; |
| 231 } | 227 } |
| 232 } | 228 } |
| 233 if ((first == 0) && (last == (len - 1))) { | 229 if ((first == 0) && (last == (len - 1))) { |
| 234 // Returns this string if it does not have leading or trailing | 230 // Returns this string if it does not have leading or trailing |
| 235 // whitespaces. | 231 // whitespaces. |
| 236 return this; | 232 return this; |
| 237 } else { | 233 } else { |
| 238 return _substringUnchecked(first, last + 1); | 234 return _substringUnchecked(first, last + 1); |
| 239 } | 235 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 String _splitMapJoinEmptyString(String onMatch(Match match), | 289 String _splitMapJoinEmptyString(String onMatch(Match match), |
| 294 String onNonMatch(String nonMatch)) { | 290 String onNonMatch(String nonMatch)) { |
| 295 // Pattern is the empty string. | 291 // Pattern is the empty string. |
| 296 StringBuffer buffer = new StringBuffer(); | 292 StringBuffer buffer = new StringBuffer(); |
| 297 int length = this.length; | 293 int length = this.length; |
| 298 int i = 0; | 294 int i = 0; |
| 299 buffer.add(onNonMatch("")); | 295 buffer.add(onNonMatch("")); |
| 300 while (i < length) { | 296 while (i < length) { |
| 301 buffer.add(onMatch(new _StringMatch(i, this, ""))); | 297 buffer.add(onMatch(new _StringMatch(i, this, ""))); |
| 302 // Special case to avoid splitting a surrogate pair. | 298 // Special case to avoid splitting a surrogate pair. |
| 303 int code = this.charCodeAt(i); | 299 int code = this.codeUnitAt(i); |
| 304 if ((code & ~0x3FF) == 0xD800 && length > i + 1) { | 300 if ((code & ~0x3FF) == 0xD800 && length > i + 1) { |
| 305 // Leading surrogate; | 301 // Leading surrogate; |
| 306 code = this.charCodeAt(i + 1); | 302 code = this.codeUnitAt(i + 1); |
| 307 if ((code & ~0x3FF) == 0xDC00) { | 303 if ((code & ~0x3FF) == 0xDC00) { |
| 308 // Matching trailing surrogate. | 304 // Matching trailing surrogate. |
| 309 buffer.add(onNonMatch(this.substring(i, i + 2))); | 305 buffer.add(onNonMatch(this.substring(i, i + 2))); |
| 310 i += 2; | 306 i += 2; |
| 311 continue; | 307 continue; |
| 312 } | 308 } |
| 313 } | 309 } |
| 314 buffer.add(onNonMatch(this[i])); | 310 buffer.add(onNonMatch(this[i])); |
| 315 i++; | 311 i++; |
| 316 } | 312 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 ++startIndex; // empty match, advance and restart | 372 ++startIndex; // empty match, advance and restart |
| 377 } else { | 373 } else { |
| 378 startIndex = endIndex; | 374 startIndex = endIndex; |
| 379 } | 375 } |
| 380 } | 376 } |
| 381 return result; | 377 return result; |
| 382 } | 378 } |
| 383 | 379 |
| 384 List<String> split(Pattern pattern) { | 380 List<String> split(Pattern pattern) { |
| 385 if ((pattern is String) && pattern.isEmpty) { | 381 if ((pattern is String) && pattern.isEmpty) { |
| 386 return splitChars(); | 382 List<String> result = new List<String>(length); |
| 383 for (int i = 0; i < length; i++) { | |
| 384 result[i] = this[i]; | |
| 385 } | |
| 386 return result; | |
| 387 } | 387 } |
| 388 int length = this.length; | 388 int length = this.length; |
| 389 Iterator iterator = pattern.allMatches(this).iterator; | 389 Iterator iterator = pattern.allMatches(this).iterator; |
| 390 if (length == 0 && iterator.moveNext()) { | 390 if (length == 0 && iterator.moveNext()) { |
| 391 // A matched empty string input returns the empty list. | 391 // A matched empty string input returns the empty list. |
| 392 return <String>[]; | 392 return <String>[]; |
| 393 } | 393 } |
| 394 List<String> result = new List<String>(); | 394 List<String> result = new List<String>(); |
| 395 int startIndex = 0; | 395 int startIndex = 0; |
| 396 int previousIndex = 0; | 396 int previousIndex = 0; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 408 if (startIndex == endIndex && endIndex == previousIndex) { | 408 if (startIndex == endIndex && endIndex == previousIndex) { |
| 409 ++startIndex; // empty match, advance and restart | 409 ++startIndex; // empty match, advance and restart |
| 410 continue; | 410 continue; |
| 411 } | 411 } |
| 412 result.add(this._substringUnchecked(previousIndex, match.start)); | 412 result.add(this._substringUnchecked(previousIndex, match.start)); |
| 413 startIndex = previousIndex = endIndex; | 413 startIndex = previousIndex = endIndex; |
| 414 } | 414 } |
| 415 return result; | 415 return result; |
| 416 } | 416 } |
| 417 | 417 |
| 418 List<String> splitChars() { | 418 List<int> get codeUnits => new CodeUnits(this); |
|
srdjan
2013/02/19 17:28:44
How does this work? Does it run in checked mode?
Lasse Reichstein Nielsen
2013/02/20 06:38:23
Yes. CodeUnits was changed to be a List (extends U
| |
| 419 int len = this.length; | |
| 420 final result = new List<String>.fixedLength(len); | |
| 421 for (int i = 0; i < len; i++) { | |
| 422 result[i] = this[i]; | |
| 423 } | |
| 424 return result; | |
| 425 } | |
| 426 | |
| 427 List<int> get charCodes { | |
| 428 int len = this.length; | |
| 429 final result = new List<int>.fixedLength(len); | |
| 430 for (int i = 0; i < len; i++) { | |
| 431 result[i] = this.charCodeAt(i); | |
| 432 } | |
| 433 return result; | |
| 434 } | |
| 435 | |
| 436 Iterable<int> get codeUnits => new CodeUnits(this); | |
| 437 | 419 |
| 438 Runes get runes => new Runes(this); | 420 Runes get runes => new Runes(this); |
| 439 | 421 |
| 440 String toUpperCase() native "String_toUpperCase"; | 422 String toUpperCase() native "String_toUpperCase"; |
| 441 | 423 |
| 442 String toLowerCase() native "String_toLowerCase"; | 424 String toLowerCase() native "String_toLowerCase"; |
| 443 | 425 |
| 444 // Implementations of Strings methods follow below. | 426 // Implementations of Strings methods follow below. |
| 445 static String join(Iterable<String> strings, String separator) { | 427 static String join(Iterable<String> strings, String separator) { |
| 446 bool first = true; | 428 bool first = true; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 500 } | 482 } |
| 501 | 483 |
| 502 String _substringUncheckedNative(int startIndex, int endIndex) | 484 String _substringUncheckedNative(int startIndex, int endIndex) |
| 503 native "OneByteString_substringUnchecked"; | 485 native "OneByteString_substringUnchecked"; |
| 504 | 486 |
| 505 List<String> _splitWithCharCode(int charCode) | 487 List<String> _splitWithCharCode(int charCode) |
| 506 native "OneByteString_splitWithCharCode"; | 488 native "OneByteString_splitWithCharCode"; |
| 507 | 489 |
| 508 List<String> split(Pattern pattern) { | 490 List<String> split(Pattern pattern) { |
| 509 if ((pattern is _OneByteString) && (pattern.length == 1)) { | 491 if ((pattern is _OneByteString) && (pattern.length == 1)) { |
| 510 return _splitWithCharCode(pattern.charCodeAt(0)); | 492 return _splitWithCharCode(pattern.codeUnitAt(0)); |
| 511 } | 493 } |
| 512 return super.split(pattern); | 494 return super.split(pattern); |
| 513 } | 495 } |
| 514 } | 496 } |
| 515 | 497 |
| 516 | 498 |
| 517 class _TwoByteString extends _StringBase implements String { | 499 class _TwoByteString extends _StringBase implements String { |
| 518 factory _TwoByteString._uninstantiable() { | 500 factory _TwoByteString._uninstantiable() { |
| 519 throw new UnsupportedError( | 501 throw new UnsupportedError( |
| 520 "_TwoByteString can only be allocated by the VM"); | 502 "_TwoByteString can only be allocated by the VM"); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 620 for (int g in groups) { | 602 for (int g in groups) { |
| 621 result.add(group(g)); | 603 result.add(group(g)); |
| 622 } | 604 } |
| 623 return result; | 605 return result; |
| 624 } | 606 } |
| 625 | 607 |
| 626 final int start; | 608 final int start; |
| 627 final String str; | 609 final String str; |
| 628 final String pattern; | 610 final String pattern; |
| 629 } | 611 } |
| OLD | NEW |