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 |