| 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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |