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

Side by Side Diff: pkg/compiler/lib/src/helpers/stats.dart

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 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
« no previous file with comments | « pkg/compiler/lib/src/helpers/helpers.dart ('k') | pkg/compiler/lib/src/helpers/trace.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 import 'dart:async' show 5 import 'dart:async' show EventSink;
6 EventSink;
7 import 'dart:collection'; 6 import 'dart:collection';
8 import 'dart:convert'; 7 import 'dart:convert';
9 8
10 import '../../compiler.dart'; 9 import '../../compiler.dart';
11 import '../common.dart'; 10 import '../common.dart';
12 import '../compiler.dart' show 11 import '../compiler.dart' show Compiler;
13 Compiler;
14 import '../util/util.dart'; 12 import '../util/util.dart';
15 13
16
17 // Helper methods for statistics. 14 // Helper methods for statistics.
18 15
19 /// Current stats collector. Use [enableStatsOutput] to enable recording of 16 /// Current stats collector. Use [enableStatsOutput] to enable recording of
20 /// stats. 17 /// stats.
21 Stats get stats { 18 Stats get stats {
22 enableDebugMode(); 19 enableDebugMode();
23 if (_stats == null) { 20 if (_stats == null) {
24 _stats = const Stats(); 21 _stats = const Stats();
25 } 22 }
26 return _stats; 23 return _stats;
27 } 24 }
28 25
29 Stats _stats; 26 Stats _stats;
30 27
31 /// Enable recording of stats. Use [Stats.dumpStats] to output the record stats. 28 /// Enable recording of stats. Use [Stats.dumpStats] to output the record stats.
32 /// 29 ///
33 /// Pass the [outputProvider] of [Compiler] to generate stats into a separate 30 /// Pass the [outputProvider] of [Compiler] to generate stats into a separate
34 /// file using [name] and [extension] for the filename. If omitted, stats are 31 /// file using [name] and [extension] for the filename. If omitted, stats are
35 /// printed on standard out. 32 /// printed on standard out.
36 /// 33 ///
37 /// If [xml] is `true`, stats output is formatted as XML with a default 34 /// If [xml] is `true`, stats output is formatted as XML with a default
38 /// extension of 'xml', otherwise the output is indented text with a default 35 /// extension of 'xml', otherwise the output is indented text with a default
39 /// extension of 'log'. 36 /// extension of 'log'.
40 void enableStatsOutput({CompilerOutputProvider outputProvider, 37 void enableStatsOutput(
41 bool xml: true, 38 {CompilerOutputProvider outputProvider,
42 String name: 'stats', 39 bool xml: true,
43 String extension, 40 String name: 'stats',
44 int examples: 10}) { 41 String extension,
42 int examples: 10}) {
45 if (_stats != null) { 43 if (_stats != null) {
46 throw new StateError('Stats have already been initialized.'); 44 throw new StateError('Stats have already been initialized.');
47 } 45 }
48 enableDebugMode(); 46 enableDebugMode();
49 47
50 StatsOutput output; 48 StatsOutput output;
51 if (outputProvider != null) { 49 if (outputProvider != null) {
52 if (extension == null) { 50 if (extension == null) {
53 extension = xml ? 'xml' : 'log'; 51 extension = xml ? 'xml' : 'log';
54 } 52 }
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 /// [a] and [b]: 188 /// [a] and [b]:
191 /// 189 ///
192 /// 'idA && idB' lists the elements both in [a] and [b], 190 /// 'idA && idB' lists the elements both in [a] and [b],
193 /// '!idA && idB' lists the elements not in [a] but in [b], and 191 /// '!idA && idB' lists the elements not in [a] but in [b], and
194 /// 'idA && !idB' lists the elements in [a] but not in [b]. 192 /// 'idA && !idB' lists the elements in [a] but not in [b].
195 /// 193 ///
196 /// If [dataA] and/or [dataB] are provided, additional information on the 194 /// If [dataA] and/or [dataB] are provided, additional information on the
197 /// elements are looked up in [dataA] or [dataB] using [dataA] as the primary 195 /// elements are looked up in [dataA] or [dataB] using [dataA] as the primary
198 /// source. 196 /// source.
199 void dumpCorrelation(idA, Iterable a, idB, Iterable b, 197 void dumpCorrelation(idA, Iterable a, idB, Iterable b,
200 {Map dataA, Map dataB}) {} 198 {Map dataA, Map dataB}) {}
201 } 199 }
202 200
203 /// Interface for printing output data. 201 /// Interface for printing output data.
204 /// 202 ///
205 /// This class serves as the disabled output. 203 /// This class serves as the disabled output.
206 class StatsOutput { 204 class StatsOutput {
207 const StatsOutput(); 205 const StatsOutput();
208 206
209 /// Print [text] as on a separate line. 207 /// Print [text] as on a separate line.
210 void println(String text) {} 208 void println(String text) {}
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 start(id); 241 start(id);
244 createGroupContent(); 242 createGroupContent();
245 end(id); 243 end(id);
246 } 244 }
247 245
248 /// End a group [id]. 246 /// End a group [id].
249 void end(String id) {} 247 void end(String id) {}
250 248
251 /// Start a stat entry for [id] with additional [data]. 249 /// Start a stat entry for [id] with additional [data].
252 void open(String id, 250 void open(String id,
253 [Map<String, dynamic> data = const <String, dynamic>{}]) {} 251 [Map<String, dynamic> data = const <String, dynamic>{}]) {}
254 252
255 /// Create a stat entry for [id] with additional [data] and content created by 253 /// Create a stat entry for [id] with additional [data] and content created by
256 /// [createChildContent]. 254 /// [createChildContent].
257 void child(String id, 255 void child(String id,
258 [Map<String, dynamic> data = const <String, dynamic>{}, 256 [Map<String, dynamic> data = const <String, dynamic>{},
259 void createChildContent()]) { 257 void createChildContent()]) {
260 open(id, data); 258 open(id, data);
261 if (createChildContent != null) createChildContent(); 259 if (createChildContent != null) createChildContent();
262 close(id); 260 close(id);
263 } 261 }
264 262
265 /// End a stat entry for [id]. 263 /// End a stat entry for [id].
266 void close(String id) {} 264 void close(String id) {}
267 265
268 /// Starts a group of additional information. 266 /// Starts a group of additional information.
269 void beginExtra() {} 267 void beginExtra() {}
270 268
271 /// Starts a group of additional information. 269 /// Starts a group of additional information.
272 void endExtra() {} 270 void endExtra() {}
273 } 271 }
274 272
275 /// Abstract base class for [ConsolePrinter] and [XMLPrinter]. 273 /// Abstract base class for [ConsolePrinter] and [XMLPrinter].
276 abstract class BasePrinter extends StatsPrinter with Indentation { 274 abstract class BasePrinter extends StatsPrinter with Indentation {
277 final int examples; 275 final int examples;
278 final StatsOutput output; 276 final StatsOutput output;
279 277
280 BasePrinter({this.output: const DebugOutput(), 278 BasePrinter({this.output: const DebugOutput(), this.examples: 10}) {
281 this.examples: 10}) {
282 indentationUnit = " "; 279 indentationUnit = " ";
283 } 280 }
284 } 281 }
285 282
286 /// [StatsPrinter] that displays stats in console lines. 283 /// [StatsPrinter] that displays stats in console lines.
287 class ConsolePrinter extends BasePrinter { 284 class ConsolePrinter extends BasePrinter {
288 int extraLevel = 0; 285 int extraLevel = 0;
289 286
290 ConsolePrinter({StatsOutput output: const DebugOutput(), 287 ConsolePrinter({StatsOutput output: const DebugOutput(), int examples: 10})
291 int examples: 10})
292 : super(output: output, examples: examples); 288 : super(output: output, examples: examples);
293 289
294 void open(String id, 290 void open(String id,
295 [Map<String, dynamic> data = const <String, dynamic>{}]) { 291 [Map<String, dynamic> data = const <String, dynamic>{}]) {
296 if (extraLevel > 0) return; 292 if (extraLevel > 0) return;
297 293
298 StringBuffer sb = new StringBuffer(); 294 StringBuffer sb = new StringBuffer();
299 sb.write(indentation); 295 sb.write(indentation);
300 String space = ''; 296 String space = '';
301 if (data['title'] != null) { 297 if (data['title'] != null) {
302 sb.write('${data['title']}:'); 298 sb.write('${data['title']}:');
303 space = ' '; 299 space = ' ';
304 data.remove('title'); 300 data.remove('title');
305 } else if (data['name'] != null) { 301 } else if (data['name'] != null) {
(...skipping 28 matching lines...) Expand all
334 void endExtra() { 330 void endExtra() {
335 extraLevel--; 331 extraLevel--;
336 } 332 }
337 } 333 }
338 334
339 /// [StatsPrinter] that displays stats in XML format. 335 /// [StatsPrinter] that displays stats in XML format.
340 class XMLPrinter extends BasePrinter { 336 class XMLPrinter extends BasePrinter {
341 static const HtmlEscape escape = const HtmlEscape(); 337 static const HtmlEscape escape = const HtmlEscape();
342 bool opened = false; 338 bool opened = false;
343 339
344 XMLPrinter({output: const DebugOutput(), 340 XMLPrinter({output: const DebugOutput(), int examples: 10})
345 int examples: 10})
346 : super(output: output, examples: examples); 341 : super(output: output, examples: examples);
347 342
348 void start(String id) { 343 void start(String id) {
349 if (!opened) { 344 if (!opened) {
350 output.println('<?xml version="1.0" encoding="UTF-8"?>'); 345 output.println('<?xml version="1.0" encoding="UTF-8"?>');
351 opened = true; 346 opened = true;
352 } 347 }
353 open(id); 348 open(id);
354 } 349 }
355 350
356 void end(String id) { 351 void end(String id) {
357 close(id); 352 close(id);
358 } 353 }
359 354
360 void open(String id, 355 void open(String id,
361 [Map<String, dynamic> data = const <String, dynamic>{}]) { 356 [Map<String, dynamic> data = const <String, dynamic>{}]) {
362 StringBuffer sb = new StringBuffer(); 357 StringBuffer sb = new StringBuffer();
363 sb.write(indentation); 358 sb.write(indentation);
364 sb.write('<$id'); 359 sb.write('<$id');
365 data.forEach((key, value) { 360 data.forEach((key, value) {
366 if (value != null) { 361 if (value != null) {
367 sb.write(' $key="${escape.convert('$value')}"'); 362 sb.write(' $key="${escape.convert('$value')}"');
368 } 363 }
369 }); 364 });
370 sb.write('>'); 365 sb.write('>');
371 output.println(sb.toString()); 366 output.println(sb.toString());
(...skipping 21 matching lines...) Expand all
393 List<StackTraceLine> commonPrefix; 388 List<StackTraceLine> commonPrefix;
394 List<_StackTraceNode> subtraces; 389 List<_StackTraceNode> subtraces;
395 390
396 _StackTraceNode(this.commonPrefix, this.count, this.subtraces); 391 _StackTraceNode(this.commonPrefix, this.count, this.subtraces);
397 392
398 _StackTraceNode.root() : this([], 0, []); 393 _StackTraceNode.root() : this([], 0, []);
399 394
400 _StackTraceNode.leaf(StackTraceLines stackTrace) 395 _StackTraceNode.leaf(StackTraceLines stackTrace)
401 : this(stackTrace.lines, 1, const []); 396 : this(stackTrace.lines, 1, const []);
402 397
403 _StackTraceNode.node(List<StackTraceLine> commonPrefix, 398 _StackTraceNode.node(List<StackTraceLine> commonPrefix, _StackTraceNode first,
404 _StackTraceNode first, 399 _StackTraceNode second)
405 _StackTraceNode second)
406 : this(commonPrefix, first.count + second.count, [first, second]); 400 : this(commonPrefix, first.count + second.count, [first, second]);
407 401
408 void add(StackTraceLines stackTrace) { 402 void add(StackTraceLines stackTrace) {
409 count++; 403 count++;
410 if (!stackTrace.lines.isEmpty) { 404 if (!stackTrace.lines.isEmpty) {
411 addSubtrace(stackTrace); 405 addSubtrace(stackTrace);
412 } 406 }
413 } 407 }
414 408
415 void addSubtrace(StackTraceLines stackTrace) { 409 void addSubtrace(StackTraceLines stackTrace) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 final id; 490 final id;
497 int totalCount = 0; 491 int totalCount = 0;
498 final int sampleFrequency; 492 final int sampleFrequency;
499 493
500 _StackTraceTree(this.id, this.sampleFrequency) : super.root(); 494 _StackTraceTree(this.id, this.sampleFrequency) : super.root();
501 495
502 void dumpTraces(StatsPrinter printer) { 496 void dumpTraces(StatsPrinter printer) {
503 printer.open('trace', { 497 printer.open('trace', {
504 'id': id, 498 'id': id,
505 'totalCount': totalCount, 499 'totalCount': totalCount,
506 'sampleFrequency': sampleFrequency}); 500 'sampleFrequency': sampleFrequency
501 });
507 dumpSubtraces(printer); 502 dumpSubtraces(printer);
508 printer.close('trace'); 503 printer.close('trace');
509 } 504 }
510 505
511 void sample() { 506 void sample() {
512 if (totalCount++ % sampleFrequency == 0) { 507 if (totalCount++ % sampleFrequency == 0) {
513 add(stackTrace(offset: 3)); 508 add(stackTrace(offset: 3));
514 } 509 }
515 } 510 }
516 } 511 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 } 564 }
570 565
571 void recordElement(key, element, {data}) { 566 void recordElement(key, element, {data}) {
572 setsMap.putIfAbsent(key, () => new Map())[element] = data; 567 setsMap.putIfAbsent(key, () => new Map())[element] = data;
573 } 568 }
574 569
575 void recordTrace(key, {int sampleFrequency}) { 570 void recordTrace(key, {int sampleFrequency}) {
576 if (sampleFrequency == null) { 571 if (sampleFrequency == null) {
577 sampleFrequency = stackTraceSampleFrequency; 572 sampleFrequency = stackTraceSampleFrequency;
578 } 573 }
579 traceMap.putIfAbsent(key, 574 traceMap
580 () => new _StackTraceTree(key, sampleFrequency)).sample(); 575 .putIfAbsent(key, () => new _StackTraceTree(key, sampleFrequency))
581 576 .sample();
582 } 577 }
583 578
584 Iterable getList(String key) { 579 Iterable getList(String key) {
585 Map map = setsMap[key]; 580 Map map = setsMap[key];
586 if (map == null) return const []; 581 if (map == null) return const [];
587 return map.keys; 582 return map.keys;
588 } 583 }
589 584
590 void dumpStats({void beforeClose()}) { 585 void dumpStats({void beforeClose()}) {
591 printer.start('stats'); 586 printer.start('stats');
592 dumpFrequencies(); 587 dumpFrequencies();
593 dumpSets(); 588 dumpSets();
594 dumpCounters(); 589 dumpCounters();
595 dumpTraces(); 590 dumpTraces();
596 if (beforeClose != null) { 591 if (beforeClose != null) {
597 beforeClose(); 592 beforeClose();
598 } 593 }
599 printer.end('stats'); 594 printer.end('stats');
600 } 595 }
601 596
602 void dumpSets() { 597 void dumpSets() {
603 printer.group('sets', () { 598 printer.group('sets', () {
604 setsMap.forEach((k, set) { 599 setsMap.forEach((k, set) {
605 dumpIterable('examples', '$k', set.keys, 600 dumpIterable('examples', '$k', set.keys,
606 limit: printer.examples, dataMap: set); 601 limit: printer.examples, dataMap: set);
607 }); 602 });
608 }); 603 });
609
610 } 604 }
611 605
612 void dumpFrequencies() { 606 void dumpFrequencies() {
613 printer.group('frequencies', () { 607 printer.group('frequencies', () {
614 frequencyMaps.forEach((key, Map<dynamic, List> map) { 608 frequencyMaps.forEach((key, Map<dynamic, List> map) {
615 printer.child('frequency', {'title': '$key'}, () { 609 printer.child('frequency', {'title': '$key'}, () {
616 dumpFrequency(map); 610 dumpFrequency(map);
617 }); 611 });
618 }); 612 });
619 }); 613 });
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 printer.open('counter', {'title': '$id', 'count': count}); 654 printer.open('counter', {'title': '$id', 'count': count});
661 result.forEach((int count, Set examples) { 655 result.forEach((int count, Set examples) {
662 if (counter == printer.examples) { 656 if (counter == printer.examples) {
663 printer.beginExtra(); 657 printer.beginExtra();
664 hasMore = true; 658 hasMore = true;
665 } 659 }
666 if (examples.length == 1 && 660 if (examples.length == 1 &&
667 (examplesLimit == 0 || !hasData(examples.first))) { 661 (examplesLimit == 0 || !hasData(examples.first))) {
668 printer.child('examples', {'count': count, 'example': examples.first}); 662 printer.child('examples', {'count': count, 'example': examples.first});
669 } else { 663 } else {
670 printer.child('examples', 664 printer.child('examples', {'count': count, 'examples': examples.length},
671 {'count': count, 'examples': examples.length},
672 () { 665 () {
673 examples.forEach((example) { 666 examples.forEach((example) {
674 dumpIterable( 667 dumpIterable('examples', '$example', map[example],
675 'examples', '$example', map[example], 668 limit: examplesLimit, includeCount: false);
676 limit: examplesLimit,
677 includeCount: false);
678 }); 669 });
679 }); 670 });
680 } 671 }
681 counter++; 672 counter++;
682 }); 673 });
683 if (hasMore) { 674 if (hasMore) {
684 printer.endExtra(); 675 printer.endExtra();
685 } 676 }
686 printer.close('counter'); 677 printer.close('counter');
687 } 678 }
688 679
689 void dumpTraces() { 680 void dumpTraces() {
690 printer.group('traces', () { 681 printer.group('traces', () {
691 traceMap.keys.forEach(dumpTrace); 682 traceMap.keys.forEach(dumpTrace);
692 }); 683 });
693 } 684 }
694 685
695 void dumpTrace(key) { 686 void dumpTrace(key) {
696 _StackTraceTree tree = traceMap[key]; 687 _StackTraceTree tree = traceMap[key];
697 tree.dumpTraces(printer); 688 tree.dumpTraces(printer);
698 } 689 }
699 690
700 void dumpCorrelation(keyA, Iterable a, keyB, Iterable b, 691 void dumpCorrelation(keyA, Iterable a, keyB, Iterable b,
701 {Map dataA, Map dataB}) { 692 {Map dataA, Map dataB}) {
702 printer.child('correlations', {'title': '$keyA vs $keyB'}, () { 693 printer.child('correlations', {'title': '$keyA vs $keyB'}, () {
703 List aAndB = a.where((e) => e != null && b.contains(e)).toList(); 694 List aAndB = a.where((e) => e != null && b.contains(e)).toList();
704 List aAndNotB = a.where((e) => e != null && !b.contains(e)).toList(); 695 List aAndNotB = a.where((e) => e != null && !b.contains(e)).toList();
705 List notAandB = b.where((e) => e != null && !a.contains(e)).toList(); 696 List notAandB = b.where((e) => e != null && !a.contains(e)).toList();
706 dumpIterable('correlation', '$keyA && $keyB', aAndB, dataMap: dataA, 697 dumpIterable('correlation', '$keyA && $keyB', aAndB,
707 limit: printer.examples); 698 dataMap: dataA, limit: printer.examples);
708 dumpIterable('correlation', '$keyA && !$keyB', aAndNotB, dataMap: dataA, 699 dumpIterable('correlation', '$keyA && !$keyB', aAndNotB,
709 limit: printer.examples); 700 dataMap: dataA, limit: printer.examples);
710 dumpIterable('correlation', '!$keyA && $keyB', notAandB, dataMap: dataB, 701 dumpIterable('correlation', '!$keyA && $keyB', notAandB,
711 limit: printer.examples); 702 dataMap: dataB, limit: printer.examples);
712 }); 703 });
713 } 704 }
714 705
715 void dumpIterable(String tag, String title, Iterable iterable, 706 void dumpIterable(String tag, String title, Iterable iterable,
716 {int limit, Map dataMap, bool includeCount: true}) { 707 {int limit, Map dataMap, bool includeCount: true}) {
717 if (limit == 0) return; 708 if (limit == 0) return;
718 709
719 Map childData = {}; 710 Map childData = {};
720 Iterable nonNullIterable = iterable.where((e) => e != null); 711 Iterable nonNullIterable = iterable.where((e) => e != null);
721 if (nonNullIterable.isEmpty && !includeCount) { 712 if (nonNullIterable.isEmpty && !includeCount) {
722 childData['name'] = title; 713 childData['name'] = title;
723 } else { 714 } else {
724 childData['title'] = title; 715 childData['title'] = title;
725 } 716 }
726 if (includeCount) { 717 if (includeCount) {
(...skipping 24 matching lines...) Expand all
751 742
752 /// Returns a map that is an inversion of [map], where the keys are the values 743 /// Returns a map that is an inversion of [map], where the keys are the values
753 /// of [map] and the values are the set of keys in [map] that share values. 744 /// of [map] and the values are the set of keys in [map] that share values.
754 /// 745 ///
755 /// If [equals] and [hashCode] are provided, these are used to determine 746 /// If [equals] and [hashCode] are provided, these are used to determine
756 /// equality among the values of [map]. 747 /// equality among the values of [map].
757 /// 748 ///
758 /// If [isValidKey] is provided, this is used to determine with a value of [map] 749 /// If [isValidKey] is provided, this is used to determine with a value of [map]
759 /// is a potential key of the inversion map. 750 /// is a potential key of the inversion map.
760 Map<dynamic, Set> inverseMap(Map map, 751 Map<dynamic, Set> inverseMap(Map map,
761 {bool equals(key1, key2), 752 {bool equals(key1, key2),
762 int hashCode(key), 753 int hashCode(key),
763 bool isValidKey(potentialKey)}) { 754 bool isValidKey(potentialKey)}) {
764 Map<dynamic, Set> result = new LinkedHashMap<dynamic, Set>( 755 Map<dynamic, Set> result = new LinkedHashMap<dynamic, Set>(
765 equals: equals, hashCode: hashCode, isValidKey: isValidKey); 756 equals: equals, hashCode: hashCode, isValidKey: isValidKey);
766 map.forEach((k, v) { 757 map.forEach((k, v) {
767 if (isValidKey == null || isValidKey(v)) { 758 if (isValidKey == null || isValidKey(v)) {
768 result.putIfAbsent(v, () => new Set()).add(k); 759 result.putIfAbsent(v, () => new Set()).add(k);
769 } 760 }
770 }); 761 });
771 return result; 762 return result;
772 } 763 }
773 764
774 /// Return a new map heuristically sorted by the keys of [map]. If the first 765 /// Return a new map heuristically sorted by the keys of [map]. If the first
775 /// key of [map] is [Comparable], the keys are sorted using [sortMap] under 766 /// key of [map] is [Comparable], the keys are sorted using [sortMap] under
776 /// the assumption that all keys are [Comparable]. 767 /// the assumption that all keys are [Comparable].
777 /// Otherwise, the keys are sorted as string using their `toString` 768 /// Otherwise, the keys are sorted as string using their `toString`
778 /// representation. 769 /// representation.
779 Map trySortMap(Map map) { 770 Map trySortMap(Map map) {
780 Iterable iterable = map.keys.where((k) => k != null); 771 Iterable iterable = map.keys.where((k) => k != null);
781 if (iterable.isEmpty) return map; 772 if (iterable.isEmpty) return map;
782 var key = iterable.first; 773 var key = iterable.first;
783 if (key is Comparable) { 774 if (key is Comparable) {
784 return sortMap(map); 775 return sortMap(map);
785 } 776 }
786 return sortMap(map, (a, b) => '$a'.compareTo('$b')); 777 return sortMap(map, (a, b) => '$a'.compareTo('$b'));
787 } 778 }
788 779
789 /// Returns a new map in which the keys of [map] are sorted using [compare]. 780 /// Returns a new map in which the keys of [map] are sorted using [compare].
790 /// If [compare] is null, the keys must be [Comparable]. 781 /// If [compare] is null, the keys must be [Comparable].
791 Map sortMap(Map map, [int compare(a,b)]) { 782 Map sortMap(Map map, [int compare(a, b)]) {
792 List keys = map.keys.toList(); 783 List keys = map.keys.toList();
793 keys.sort(compare); 784 keys.sort(compare);
794 Map sortedMap = new Map(); 785 Map sortedMap = new Map();
795 keys.forEach((k) => sortedMap[k] = map[k]); 786 keys.forEach((k) => sortedMap[k] = map[k]);
796 return sortedMap; 787 return sortedMap;
797 } 788 }
798
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/helpers/helpers.dart ('k') | pkg/compiler/lib/src/helpers/trace.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698