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 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 25 matching lines...) Expand all Loading... | |
| 44 factory _StringBase._uninstantiable() { | 52 factory _StringBase._uninstantiable() { |
| 45 throw new UnsupportedError( | 53 throw new UnsupportedError( |
| 46 "_StringBase can't be instaniated"); | 54 "_StringBase can't be instaniated"); |
| 47 } | 55 } |
| 48 | 56 |
| 49 Type get runtimeType => String; | 57 Type get runtimeType => String; |
| 50 | 58 |
| 51 int get hashCode native "String_getHashCode"; | 59 int get hashCode native "String_getHashCode"; |
| 52 | 60 |
| 53 /** | 61 /** |
| 54 * Create the most efficient string representation for specified | 62 * Create the most efficient string representation for specified |
| 55 * [codePoints]. | 63 * [codePoints]. |
|
siva
2015/01/20 23:50:26
The parameter name is not documented correctly, th
Lasse Reichstein Nielsen
2015/01/22 07:16:32
Done.
| |
| 64 * | |
| 65 * The [limit] is an upper limit on the character codes in the iterable. | |
| 66 * It's `null` if unknown. | |
|
siva
2015/01/20 23:50:26
Since limit is documented maybe we should also doc
Lasse Reichstein Nielsen
2015/01/22 07:16:33
Done.
| |
| 56 */ | 67 */ |
| 57 static String createFromCharCodes(Iterable<int> charCodes, | 68 static String createFromCharCodes(Iterable<int> charCodes, |
| 58 int start, int end) { | 69 int start, int end, |
| 70 int limit) { | |
| 71 if (start == null) throw new ArgumentError.notNull("start"); | |
| 59 if (charCodes == null) throw new ArgumentError(charCodes); | 72 if (charCodes == null) throw new ArgumentError(charCodes); |
| 60 // TODO(srdjan): Also skip copying of wide typed arrays. | 73 // TODO(srdjan): Also skip copying of wide typed arrays. |
| 61 final ccid = ClassID.getID(charCodes); | 74 final ccid = ClassID.getID(charCodes); |
| 62 bool isOneByteString = false; | 75 bool isOneByteString = false; |
| 63 if ((ccid != ClassID.cidArray) && | 76 if ((ccid != ClassID.cidArray) && |
| 64 (ccid != ClassID.cidGrowableObjectArray) && | 77 (ccid != ClassID.cidGrowableObjectArray) && |
| 65 (ccid != ClassID.cidImmutableArray)) { | 78 (ccid != ClassID.cidImmutableArray)) { |
| 66 if (charCodes is Uint8List) { | 79 if (charCodes is Uint8List) { |
| 67 isOneByteString = true; | 80 end = RangeError.checkValidRange(start, end, charCodes.length); |
| 68 } else { | 81 return _createOneByteString(charCodes, start, end - start); |
| 69 // Treat charCodes as Iterable. | 82 } else if (charCodes is! Uint16List) { |
| 70 if (start < 0) throw new RangeError.range(start, 0, charCodes.length); | 83 return _createStringFromIterable(charCodes, start, end); |
| 71 if (end != null && end < start) { | |
| 72 throw new RangeError.range(end, start, charCodes.length); | |
| 73 } | |
| 74 var it = charCodes.iterator; | |
| 75 for (int i = 0; i < start; i++) { | |
| 76 if (!it.moveNext()) { | |
| 77 throw new RangeError.range(start, 0, i); | |
| 78 } | |
| 79 } | |
| 80 int bits = 0; // Bitwise or of all char codes in list. | |
| 81 var list = []; | |
| 82 if (end == null) { | |
| 83 while (it.moveNext()) { | |
| 84 int code = it.current; | |
| 85 bits |= code; | |
| 86 list.add(code); | |
| 87 } | |
| 88 } else { | |
| 89 for (int i = start; i < end; i++) { | |
| 90 if (!it.moveNext()) { | |
| 91 throw new RangeError.range(end, start, i); | |
| 92 } | |
| 93 int code = it.current; | |
| 94 bits |= code; | |
| 95 list.add(code); | |
| 96 } | |
| 97 } | |
| 98 charCodes = list; | |
| 99 isOneByteString = (bits >= 0 && bits <= 0xff); | |
| 100 start = 0; | |
| 101 end = list.length; | |
| 102 } | 84 } |
| 103 } | 85 } |
| 104 int codeCount = charCodes.length; | 86 int codeCount = charCodes.length; |
| 105 if (start < 0 || start > codeCount) { | 87 end = RangeError.checkValidRange(start, end, codeCount); |
| 106 throw new RangeError.range(start, 0, codeCount); | |
| 107 } | |
| 108 if (end == null) { | |
| 109 end = codeCount; | |
| 110 } else if (end < start || end > codeCount) { | |
| 111 throw new RangeError.range(end, start, codeCount); | |
| 112 } | |
| 113 final len = end - start; | 88 final len = end - start; |
| 114 if (!isOneByteString) { | 89 if (len == 0) return ""; |
| 115 for (int i = start; i < end; i++) { | 90 if (limit == null) { |
| 116 int e = charCodes[i]; | 91 limit = _scanCodeUnits(charCodes, start, end); |
| 117 if (e is! _Smi) throw new ArgumentError(e); | 92 if (limit < 0) { |
| 118 // Is e Latin1? | 93 throw new ArgumentError(charCodes); |
| 119 if ((e < 0) || (e > 0xFF)) { | |
| 120 return _createFromCodePoints(charCodes, start, end); | |
| 121 } | |
| 122 } | 94 } |
|
siva
2015/01/20 23:50:26
the (limit < 0) should be pulled outside the if (l
Lasse Reichstein Nielsen
2015/01/22 07:16:32
While that shouldn't happen (we check that elsewhe
| |
| 123 } | 95 } |
| 124 // Allocate a one byte string. When the list is 128 entries or longer, | 96 if (limit <= _maxLatin1) { |
| 125 // it's faster to perform a runtime-call. | 97 return _createOneByteString(charCodes, start, len); |
| 126 if (len >= 128) { | |
| 127 return _OneByteString._allocateFromOneByteList(charCodes, start, end); | |
| 128 } | 98 } |
|
siva
2015/01/20 23:50:26
Since you are checking for 'limit' not being < 0 a
Lasse Reichstein Nielsen
2015/01/22 07:16:32
True. I'll consider if it's worth it for another C
| |
| 99 if (limit <= _maxUtf16) { | |
| 100 return _TwoByteString._allocateFromTwoByteList(charCodes, start, end); | |
| 101 } | |
| 102 return _createFromCodePoints(charCodes, start, end); | |
|
siva
2015/01/20 23:50:26
The same TODO applies to this call of createFromCo
Lasse Reichstein Nielsen
2015/01/22 07:16:33
If we get here, then limit > 0xffff, so there is a
| |
| 103 } | |
| 104 | |
| 105 static int _scanCodeUnits(List<int> charCodes, int start, int end) { | |
| 106 int bits = 0; | |
| 107 for (int i = start; i < end; i++) { | |
| 108 int code = charCodes[i]; | |
| 109 if (code is! _Smi) throw new ArgumentError(charCodes); | |
| 110 bits |= code; | |
| 111 } | |
| 112 return bits; | |
| 113 } | |
| 114 | |
| 115 static String _createStringFromIterable(Iterable<int> charCodes, | |
| 116 int start, int end) { | |
| 117 // Treat charCodes as Iterable. | |
| 118 if (charCodes is EfficientLength) { | |
| 119 int length = charCodes.length; | |
| 120 end = RangeError.checkValidRange(start, end, length); | |
| 121 List charCodeList = new List.from(charCodes.take(end).skip(start), | |
| 122 growable: false); | |
| 123 return createFromCharCodes(charCodeList, 0, charCodeList.length, null); | |
| 124 } | |
| 125 // Don't know length of iterable, so iterate and see if all the values | |
| 126 // are there. | |
| 127 if (start < 0) throw new RangeError.range(start, 0, charCodes.length); | |
| 128 if (end != null && end < start) { | |
| 129 throw new RangeError.range(end, start, charCodes.length); | |
| 130 } | |
| 131 var it = charCodes.iterator; | |
| 132 for (int i = 0; i < start; i++) { | |
| 133 if (!it.moveNext()) { | |
| 134 throw new RangeError.range(start, 0, i); | |
| 135 } | |
| 136 } | |
| 137 List charCodeList; | |
| 138 int bits = 0; // Bitwise-or of all char codes in list. | |
| 139 if (end == null) { | |
| 140 var list = []; | |
| 141 while (it.moveNext()) { | |
| 142 int code = it.current; | |
| 143 bits |= code; | |
| 144 list.add(code); | |
| 145 } | |
| 146 charCodeList = makeListFixedLength(list); | |
| 147 } else { | |
|
siva
2015/01/20 23:50:26
why not move the end < start check here to avoid h
Lasse Reichstein Nielsen
2015/01/22 07:16:32
Done.
| |
| 148 int len = end - start; | |
| 149 var list = new List(len); | |
| 150 for (int i = 0; i < len; i++) { | |
| 151 if (!it.moveNext()) { | |
| 152 throw new RangeError.range(end, start, start + i); | |
| 153 } | |
| 154 int code = it.current; | |
| 155 bits |= code; | |
| 156 list[i] = code; | |
| 157 } | |
| 158 charCodeList = list; | |
| 159 } | |
| 160 int length = charCodeList.length; | |
| 161 if (bits < 0) throw new ArgumentError(charCodes); | |
|
siva
2015/01/20 23:50:26
This style of not using a '{' ... '}' seems incons
Lasse Reichstein Nielsen
2015/01/22 07:16:32
I use it when it fits on a line, but not consisten
| |
| 162 bool isOneByteString = (bits <= _maxLatin1); | |
| 163 if (isOneByteString) { | |
| 164 return _createOneByteString(charCodeList, 0, length); | |
| 165 } | |
| 166 return createFromCharCodes(charCodeList, 0, length, bits); | |
| 167 } | |
| 168 | |
| 169 static String _createOneByteString(List<int> charCodes, int start, int len) { | |
| 170 // It's always faster to do this in Dart than to call into the runtime. | |
| 129 var s = _OneByteString._allocate(len); | 171 var s = _OneByteString._allocate(len); |
| 130 for (int i = 0; i < len; i++) { | 172 for (int i = 0; i < len; i++) { |
| 131 s._setAt(i, charCodes[start + i]); | 173 s._setAt(i, charCodes[start + i]); |
| 132 } | 174 } |
| 133 return s; | 175 return s; |
| 134 } | 176 } |
| 135 | 177 |
| 178 static String _createTwoByteString(List<int> charCodes, int start, int len) { | |
| 179 // TODO(lrn): Create string without scanning charCodes again - all values | |
| 180 // in the [start..end] range are uint16 values. | |
| 181 return _createFromCodePoints(charCodes, start, end); | |
| 182 } | |
| 183 | |
| 136 static String _createFromCodePoints(List<int> codePoints, int start, int end) | 184 static String _createFromCodePoints(List<int> codePoints, int start, int end) |
| 137 native "StringBase_createFromCodePoints"; | 185 native "StringBase_createFromCodePoints"; |
| 138 | 186 |
| 139 String operator [](int index) native "String_charAt"; | 187 String operator [](int index) native "String_charAt"; |
| 140 | 188 |
| 141 int codeUnitAt(int index) native "String_codeUnitAt"; | 189 int codeUnitAt(int index) native "String_codeUnitAt"; |
| 142 | 190 |
| 143 int get length native "String_getLength"; | 191 int get length native "String_getLength"; |
| 144 | 192 |
| 145 bool get isEmpty { | 193 bool get isEmpty { |
| (...skipping 843 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 989 void _setAt(int index, int codePoint) native "OneByteString_setAt"; | 1037 void _setAt(int index, int codePoint) native "OneByteString_setAt"; |
| 990 } | 1038 } |
| 991 | 1039 |
| 992 | 1040 |
| 993 class _TwoByteString extends _StringBase implements String { | 1041 class _TwoByteString extends _StringBase implements String { |
| 994 factory _TwoByteString._uninstantiable() { | 1042 factory _TwoByteString._uninstantiable() { |
| 995 throw new UnsupportedError( | 1043 throw new UnsupportedError( |
| 996 "_TwoByteString can only be allocated by the VM"); | 1044 "_TwoByteString can only be allocated by the VM"); |
| 997 } | 1045 } |
| 998 | 1046 |
| 1047 static String _allocateFromTwoByteList(List list, int start, int end) | |
| 1048 native "TwoByteString_allocateFromTwoByteList"; | |
| 1049 | |
| 999 bool _isWhitespace(int codeUnit) { | 1050 bool _isWhitespace(int codeUnit) { |
| 1000 return _StringBase._isTwoByteWhitespace(codeUnit); | 1051 return _StringBase._isTwoByteWhitespace(codeUnit); |
| 1001 } | 1052 } |
| 1002 | 1053 |
| 1003 bool operator ==(Object other) { | 1054 bool operator ==(Object other) { |
| 1004 return super == other; | 1055 return super == other; |
| 1005 } | 1056 } |
| 1006 } | 1057 } |
| 1007 | 1058 |
| 1008 | 1059 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1075 class _CodeUnits extends Object with ListMixin<int>, | 1126 class _CodeUnits extends Object with ListMixin<int>, |
| 1076 UnmodifiableListMixin<int> { | 1127 UnmodifiableListMixin<int> { |
| 1077 /** The string that this is the code units of. */ | 1128 /** The string that this is the code units of. */ |
| 1078 String _string; | 1129 String _string; |
| 1079 | 1130 |
| 1080 _CodeUnits(this._string); | 1131 _CodeUnits(this._string); |
| 1081 | 1132 |
| 1082 int get length => _string.length; | 1133 int get length => _string.length; |
| 1083 int operator[](int i) => _string.codeUnitAt(i); | 1134 int operator[](int i) => _string.codeUnitAt(i); |
| 1084 } | 1135 } |
| OLD | NEW |