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 |