Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: test/generated_sdk/lib/convert/convert.dart

Issue 1162723007: remove generated_sdk from checked in code (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
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.
4
5 /**
6 *
7 * Encoders and decoders for converting between different data representations,
8 * including JSON and UTF-8.
9 *
10 * In addition to converters for common data representations, this library
11 * provides support for implementing converters in a way which makes them easy t o
12 * chain and to use with streams.
13 *
14 * The `dart:convert` library works in both web apps and command-line apps.
15 * To use it:
16 *
17 * import 'dart:convert';
18 *
19 * Two commonly used converters are the top-level instances of
20 * [JsonCodec] and [Utf8Codec], named JSON and UTF8, respectively.
21 *
22 * JSON is a simple text format for representing
23 * structured objects and collections.
24 * The JSON encoder/decoder transforms between strings and
25 * object structures, such as lists and maps, using the JSON format.
26 *
27 * UTF-8 is a common variable-width encoding that can represent
28 * every character in the Unicode character set.
29 * The UTF-8 encoder/decoder transforms between Strings and bytes.
30 *
31 * Converters are often used with streams
32 * to transform the data that comes through the stream
33 * as it becomes available.
34 * The following code uses two converters.
35 * The first is a UTF-8 decoder, which converts the data from bytes to UTF-8
36 * as it's read from a file,
37 * The second is an instance of [LineSplitter],
38 * which splits the data on newline boundaries.
39 *
40 * int lineNumber = 1;
41 * Stream<List<int>> stream = new File('quotes.txt').openRead();
42 *
43 * stream.transform(UTF8.decoder)
44 * .transform(const LineSplitter())
45 * .listen((line) {
46 * if (showLineNumbers) {
47 * stdout.write('${lineNumber++} ');
48 * }
49 * stdout.writeln(line);
50 * });
51 *
52 * See the documentation for the [Codec] and [Converter] classes
53 * for information about creating your own converters.
54 */
55 library dart.convert;
56
57 import 'dart:async';
58 import 'dart:typed_data';
59 import 'dart:_js_helper' show patch;
60 import 'dart:_foreign_helper' show JS;
61 import 'dart:_interceptors' show JSExtendableArray;
62 import 'dart:_internal' show MappedIterable, ListIterable;
63 import 'dart:collection' show Maps, LinkedHashMap;
64
65 part 'ascii.dart';
66 part 'byte_conversion.dart';
67 part 'chunked_conversion.dart';
68 part 'codec.dart';
69 part 'converter.dart';
70 part 'encoding.dart';
71 part 'html_escape.dart';
72 part 'json.dart';
73 part 'latin1.dart';
74 part 'line_splitter.dart';
75 part 'string_conversion.dart';
76 part 'utf.dart';
77
78 /**
79 * Walks the raw JavaScript value [json], replacing JavaScript Objects with
80 * Maps. [json] is expected to be freshly allocated so elements can be replaced
81 * in-place.
82 */
83 _convertJsonToDart(json, reviver(key, value)) {
84 assert(reviver != null);
85 walk(e) {
86 // JavaScript null, string, number, bool are in the correct representation.
87 if (JS('bool', '# == null', e) || JS('bool', 'typeof # != "object"', e)) {
88 return e;
89 }
90
91 // This test is needed to avoid identifing '{"__proto__":[]}' as an Array.
92 // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
93 // bug 621 below is fixed.
94 if (JS('bool', 'Object.getPrototypeOf(#) === Array.prototype', e)) {
95 // In-place update of the elements since JS Array is a Dart List.
96 for (int i = 0; i < JS('int', '#.length', e); i++) {
97 // Use JS indexing to avoid range checks. We know this is the only
98 // reference to the list, but the compiler will likely never be able to
99 // tell that this instance of the list cannot have its length changed by
100 // the reviver even though it later will be passed to the reviver at the
101 // outer level.
102 var item = JS('', '#[#]', e, i);
103 JS('', '#[#]=#', e, i, reviver(i, walk(item)));
104 }
105 return e;
106 }
107
108 // Otherwise it is a plain object, so copy to a JSON map, so we process
109 // and revive all entries recursively.
110 _JsonMap map = new _JsonMap(e);
111 var processed = map._processed;
112 List<String> keys = map._computeKeys();
113 for (int i = 0; i < keys.length; i++) {
114 String key = keys[i];
115 var revived = reviver(key, walk(JS('', '#[#]', e, key)));
116 JS('', '#[#]=#', processed, key, revived);
117 }
118
119 // Update the JSON map structure so future access is cheaper.
120 map._original = processed; // Don't keep two objects around.
121 return map;
122 }
123
124 return reviver(null, walk(json));
125 }
126 _convertJsonToDartLazy(object) {
127 // JavaScript null and undefined are represented as null.
128 if (object == null) return null;
129
130 // JavaScript string, number, bool already has the correct representation.
131 if (JS('bool', 'typeof # != "object"', object)) {
132 return object;
133 }
134
135 // This test is needed to avoid identifing '{"__proto__":[]}' as an array.
136 // TODO(sra): Replace this test with cheaper '#.constructor === Array' when
137 // bug https://code.google.com/p/v8/issues/detail?id=621 is fixed.
138 if (JS('bool', 'Object.getPrototypeOf(#) !== Array.prototype', object)) {
139 return new _JsonMap(object);
140 }
141
142 // Update the elements in place since JS arrays are Dart lists.
143 for (int i = 0; i < JS('int', '#.length', object); i++) {
144 // Use JS indexing to avoid range checks. We know this is the only
145 // reference to the list, but the compiler will likely never be able to
146 // tell that this instance of the list cannot have its length changed by
147 // the reviver even though it later will be passed to the reviver at the
148 // outer level.
149 var item = JS('', '#[#]', object, i);
150 JS('', '#[#]=#', object, i, _convertJsonToDartLazy(item));
151 }
152 return object;
153 }
154 class _JsonMap implements LinkedHashMap {
155 // The original JavaScript object remains unchanged until
156 // the map is eventually upgraded, in which case we null it
157 // out to reclaim the memory used by it.
158 var _original;
159
160 // We keep track of the map entries that we have already
161 // processed by adding them to a separate JavaScript object.
162 var _processed = _newJavaScriptObject();
163
164 // If the data slot isn't null, it represents either the list
165 // of keys (for non-upgraded JSON maps) or the upgraded map.
166 var _data = null;
167
168 _JsonMap(this._original);
169
170 operator[](Object key) {
171 if (_isUpgraded) {
172 return _upgradedMap[key];
173 } else if (key is !String) {
174 return null;
175 } else {
176 var result = _getProperty(_processed, key);
177 if (_isUnprocessed(result)) result = _process(key);
178 return result;
179 }
180 }
181
182 int get length => _isUpgraded
183 ? _upgradedMap.length
184 : _computeKeys().length;
185
186 bool get isEmpty => length == 0;
187 bool get isNotEmpty => length > 0;
188
189 Iterable get keys {
190 if (_isUpgraded) return _upgradedMap.keys;
191 return new _JsonMapKeyIterable(this);
192 }
193
194 Iterable get values {
195 if (_isUpgraded) return _upgradedMap.values;
196 return new MappedIterable(_computeKeys(), (each) => this[each]);
197 }
198
199 operator[]=(key, value) {
200 if (_isUpgraded) {
201 _upgradedMap[key] = value;
202 } else if (containsKey(key)) {
203 var processed = _processed;
204 _setProperty(processed, key, value);
205 var original = _original;
206 if (!identical(original, processed)) {
207 _setProperty(original, key, null); // Reclaim memory.
208 }
209 } else {
210 _upgrade()[key] = value;
211 }
212 }
213
214 void addAll(Map other) {
215 other.forEach((key, value) {
216 this[key] = value;
217 });
218 }
219
220 bool containsValue(Object value) {
221 if (_isUpgraded) return _upgradedMap.containsValue(value);
222 List<String> keys = _computeKeys();
223 for (int i = 0; i < keys.length; i++) {
224 String key = keys[i];
225 if (this[key] == value) return true;
226 }
227 return false;
228 }
229
230 bool containsKey(Object key) {
231 if (_isUpgraded) return _upgradedMap.containsKey(key);
232 if (key is !String) return false;
233 return _hasProperty(_original, key);
234 }
235
236 putIfAbsent(key, ifAbsent()) {
237 if (containsKey(key)) return this[key];
238 var value = ifAbsent();
239 this[key] = value;
240 return value;
241 }
242
243 remove(Object key) {
244 if (!_isUpgraded && !containsKey(key)) return null;
245 return _upgrade().remove(key);
246 }
247
248 void clear() {
249 if (_isUpgraded) {
250 _upgradedMap.clear();
251 } else {
252 if (_data != null) {
253 // Clear the list of keys to make sure we force
254 // a concurrent modification error if anyone is
255 // currently iterating over it.
256 _data.clear();
257 }
258 _original = _processed = null;
259 _data = {};
260 }
261 }
262
263 void forEach(void f(key, value)) {
264 if (_isUpgraded) return _upgradedMap.forEach(f);
265 List<String> keys = _computeKeys();
266 for (int i = 0; i < keys.length; i++) {
267 String key = keys[i];
268
269 // Compute the value under the assumption that the property
270 // is present but potentially not processed.
271 var value = _getProperty(_processed, key);
272 if (_isUnprocessed(value)) {
273 value = _convertJsonToDartLazy(_getProperty(_original, key));
274 _setProperty(_processed, key, value);
275 }
276
277 // Do the callback.
278 f(key, value);
279
280 // Check if invoking the callback function changed
281 // the key set. If so, throw an exception.
282 if (!identical(keys, _data)) {
283 throw new ConcurrentModificationError(this);
284 }
285 }
286 }
287
288 String toString() => Maps.mapToString(this);
289
290
291 // ------------------------------------------
292 // Private helper methods.
293 // ------------------------------------------
294
295 bool get _isUpgraded => _processed == null;
296
297 Map get _upgradedMap {
298 assert(_isUpgraded);
299 // 'cast' the union type to LinkedHashMap. It would be even better if we
300 // could 'cast' to the implementation type, since LinkedHashMap includes
301 // _JsonMap.
302 return JS('LinkedHashMap', '#', _data);
303 }
304
305 List<String> _computeKeys() {
306 assert(!_isUpgraded);
307 List keys = _data;
308 if (keys == null) {
309 keys = _data = _getPropertyNames(_original);
310 }
311 return JS('JSExtendableArray', '#', keys);
312 }
313
314 Map _upgrade() {
315 if (_isUpgraded) return _upgradedMap;
316
317 // Copy all the (key, value) pairs to a freshly allocated
318 // linked hash map thus preserving the ordering.
319 Map result = {};
320 List<String> keys = _computeKeys();
321 for (int i = 0; i < keys.length; i++) {
322 String key = keys[i];
323 result[key] = this[key];
324 }
325
326 // We only upgrade when we need to extend the map, so we can
327 // safely force a concurrent modification error in case
328 // someone is iterating over the map here.
329 if (keys.isEmpty) {
330 keys.add(null);
331 } else {
332 keys.clear();
333 }
334
335 // Clear out the associated JavaScript objects and mark the
336 // map as having been upgraded.
337 _original = _processed = null;
338 _data = result;
339 assert(_isUpgraded);
340 return result;
341 }
342
343 _process(String key) {
344 if (!_hasProperty(_original, key)) return null;
345 var result = _convertJsonToDartLazy(_getProperty(_original, key));
346 return _setProperty(_processed, key, result);
347 }
348
349
350 // ------------------------------------------
351 // Private JavaScript helper methods.
352 // ------------------------------------------
353
354 static bool _hasProperty(object, String key)
355 => JS('bool', 'Object.prototype.hasOwnProperty.call(#,#)', object, key);
356 static _getProperty(object, String key)
357 => JS('', '#[#]', object, key);
358 static _setProperty(object, String key, value)
359 => JS('', '#[#]=#', object, key, value);
360 static List _getPropertyNames(object)
361 => JS('JSExtendableArray', 'Object.keys(#)', object);
362 static bool _isUnprocessed(object)
363 => JS('bool', 'typeof(#)=="undefined"', object);
364 static _newJavaScriptObject()
365 => JS('=Object', 'Object.create(null)');
366 }
367 class _JsonMapKeyIterable extends ListIterable {
368 final _JsonMap _parent;
369
370 _JsonMapKeyIterable(this._parent);
371
372 int get length => _parent.length;
373
374 String elementAt(int index) {
375 return _parent._isUpgraded ? _parent.keys.elementAt(index)
376 : _parent._computeKeys()[index];
377 }
378
379 /// Although [ListIterable] defines its own iterator, we return the iterator
380 /// of the underlying list [_keys] in order to propagate
381 /// [ConcurrentModificationError]s.
382 Iterator get iterator {
383 return _parent._isUpgraded ? _parent.keys.iterator
384 : _parent._computeKeys().iterator;
385 }
386
387 /// Delegate to [parent.containsKey] to ensure the performance expected
388 /// from [Map.keys.containsKey].
389 bool contains(Object key) => _parent.containsKey(key);
390 }
391 /**
392 * Implements the chunked conversion from a JSON string to its corresponding
393 * object.
394 *
395 * The sink only creates one object, but its input can be chunked.
396 */
397 // TODO(floitsch): don't accumulate everything before starting to decode.
398 class _JsonDecoderSink extends _StringSinkConversionSink {
399 final _Reviver _reviver;
400 final Sink<Object> _sink;
401
402 _JsonDecoderSink(this._reviver, this._sink)
403 : super(new StringBuffer());
404
405 void close() {
406 super.close();
407 StringBuffer buffer = _stringSink;
408 String accumulated = buffer.toString();
409 buffer.clear();
410 Object decoded = _parseJson(accumulated, _reviver);
411 _sink.add(decoded);
412 _sink.close();
413 }
414 }
OLDNEW
« no previous file with comments | « test/generated_sdk/lib/convert/codec.dart ('k') | test/generated_sdk/lib/convert/converter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698