Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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 library barback.utils; | 5 library barback.utils; |
| 6 | 6 |
| 7 import 'dart:async'; | |
| 8 | |
| 7 /// Converts a number in the range [0-255] to a two digit hex string. | 9 /// Converts a number in the range [0-255] to a two digit hex string. |
| 8 /// | 10 /// |
| 9 /// For example, given `255`, returns `ff`. | 11 /// For example, given `255`, returns `ff`. |
| 10 String byteToHex(int byte) { | 12 String byteToHex(int byte) { |
| 11 assert(byte >= 0 && byte <= 255); | 13 assert(byte >= 0 && byte <= 255); |
| 12 | 14 |
| 13 const DIGITS = "0123456789abcdef"; | 15 const DIGITS = "0123456789abcdef"; |
| 14 return DIGITS[(byte ~/ 16) % 16] + DIGITS[byte % 16]; | 16 return DIGITS[(byte ~/ 16) % 16] + DIGITS[byte % 16]; |
| 15 } | 17 } |
| 18 | |
| 19 /// Group the elements in [iter] by the value returned by [fn]. | |
| 20 /// | |
| 21 /// This returns a map whose keys are the return values of [fn] and whose values | |
| 22 /// are lists of each element in [iter] for which [fn] returned that key. | |
| 23 Map groupBy(Iterable iter, fn(element)) { | |
| 24 var map = {}; | |
| 25 for (var element in iter) { | |
| 26 var list = map.putIfAbsent(fn(element), () => []); | |
| 27 list.add(element); | |
| 28 } | |
| 29 return map; | |
| 30 } | |
| 31 | |
| 32 /// Flattens nested lists inside an iterable into a single list containing only | |
| 33 /// non-list elements. | |
| 34 List flatten(Iterable nested) { | |
| 35 var result = []; | |
| 36 helper(list) { | |
| 37 for (var element in list) { | |
| 38 if (element is List) { | |
|
Bob Nystrom
2013/07/11 23:03:40
is Iterable
nweiz
2013/07/15 22:11:44
That seems a little dangerous. A lot of things can
Bob Nystrom
2013/07/16 17:36:01
Conversely, a lot of things extend iterable that d
nweiz
2013/07/16 19:39:39
That case is more straightforward to detect. If th
| |
| 39 helper(element); | |
| 40 } else { | |
| 41 result.add(element); | |
| 42 } | |
| 43 } | |
| 44 } | |
| 45 helper(nested); | |
| 46 return result; | |
| 47 } | |
| 48 | |
| 49 /// Passes each key/value pair in [map] to [fn] and returns a new [Map] whose | |
| 50 /// values are the return values of [fn]. | |
| 51 Map mapMapValues(Map map, fn(key, value)) => | |
| 52 new Map.fromIterable(map.keys, value: (key) => fn(key, map[key])); | |
| 53 | |
| 54 /// Merges [streams] into a single stream that emits events from all sources. | |
| 55 Stream mergeStreams(Iterable<Stream> streams) { | |
| 56 streams = streams.toList(); | |
| 57 var doneCount = 0; | |
| 58 var controller = new StreamController(sync: true); | |
|
Bob Nystrom
2013/07/11 23:03:40
Document why "sync: true"
nweiz
2013/07/15 22:11:44
Done.
| |
| 59 | |
| 60 for (var stream in streams) { | |
| 61 stream.listen((value) { | |
| 62 controller.add(value); | |
| 63 }, onError: (error) { | |
| 64 controller.addError(error); | |
| 65 }, onDone: () { | |
| 66 doneCount++; | |
| 67 if (doneCount == streams.length) controller.close(); | |
| 68 }); | |
| 69 } | |
| 70 | |
| 71 return controller.stream; | |
| 72 } | |
| 73 | |
| 74 /// Prepends each line in [text] with [prefix]. If [firstPrefix] is passed, the | |
| 75 /// first line is prefixed with that instead. | |
| 76 String prefixLines(String text, {String prefix: '| ', String firstPrefix}) { | |
| 77 var lines = text.split('\n'); | |
| 78 if (firstPrefix == null) { | |
| 79 return lines.map((line) => '$prefix$line').join('\n'); | |
| 80 } | |
| 81 | |
| 82 var firstLine = "$firstPrefix${lines.first}"; | |
| 83 lines = lines.skip(1).map((line) => '$prefix$line').toList(); | |
| 84 lines.insert(0, firstLine); | |
| 85 return lines.join('\n'); | |
| 86 } | |
| 87 | |
| 88 /// Returns a [Future] that completes after pumping the event queue [times] | |
| 89 /// times. By default, this should pump the event queue enough times to allow | |
| 90 /// any code to run, as long as it's not waiting on some external event. | |
| 91 Future pumpEventQueue([int times=20]) { | |
| 92 if (times == 0) return new Future.value(); | |
| 93 // We use a delayed future to allow runAsync events to finish. The | |
| 94 // Future.value or Future() constructors use runAsync themselves and would | |
| 95 // therefore not wait for runAsync callbacks that are scheduled after invoking | |
| 96 // this method. | |
| 97 return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1)); | |
| 98 } | |
| 99 | |
| OLD | NEW |