| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| /** |
| * Generic utility functions. Stuff that should possibly be in core. |
| */ |
| library utils; |
| |
| import 'dart:crypto'; |
| import 'dart:isolate'; |
| |
| /** A pair of values. */ |
| class Pair<E, F> { |
| E first; |
| F last; |
| |
| Pair(this.first, this.last); |
| |
| String toString() => '($first, $last)'; |
| |
| bool operator==(other) { |
| if (other is! Pair) return false; |
| return other.first == first && other.last == last; |
| } |
| } |
| |
| // TODO(rnystrom): Move into String? |
| /** Pads [source] to [length] by adding spaces at the end. */ |
| String padRight(String source, int length) { |
| final result = new StringBuffer(); |
| result.add(source); |
| |
| while (result.length < length) { |
| result.add(' '); |
| } |
| |
| return result.toString(); |
| } |
| |
| /** |
| * Runs [fn] after [future] completes, whether it completes successfully or not. |
| * Essentially an asynchronous `finally` block. |
| */ |
| always(Future future, fn()) { |
| var completer = new Completer(); |
| future.then((_) => fn()); |
| future.handleException((_) { |
| fn(); |
| return false; |
| }); |
| } |
| |
| /** |
| * Flattens nested lists into a single list containing only non-list elements. |
| */ |
| List flatten(List nested) { |
| var result = []; |
| helper(list) { |
| for (var element in list) { |
| if (element is List) { |
| helper(element); |
| } else { |
| result.add(element); |
| } |
| } |
| } |
| helper(nested); |
| return result; |
| } |
| |
| /** |
| * Asserts that [iter] contains only one element, and returns it. |
| */ |
| only(Iterable iter) { |
| var iterator = iter.iterator(); |
| assert(iterator.hasNext); |
| var obj = iterator.next(); |
| assert(!iterator.hasNext); |
| return obj; |
| } |
| |
| /** |
| * Returns a set containing all elements in [minuend] that are not in |
| * [subtrahend]. |
| */ |
| Set setMinus(Collection minuend, Collection subtrahend) { |
| var minuendSet = new Set.from(minuend); |
| minuendSet.removeAll(subtrahend); |
| return minuendSet; |
| } |
| |
| /** |
| * Replace each instance of [matcher] in [source] with the return value of [fn]. |
| */ |
| String replace(String source, Pattern matcher, String fn(Match)) { |
| var buffer = new StringBuffer(); |
| var start = 0; |
| for (var match in matcher.allMatches(source)) { |
| buffer.add(source.substring(start, match.start)); |
| start = match.end; |
| buffer.add(fn(match)); |
| } |
| buffer.add(source.substring(start)); |
| return buffer.toString(); |
| } |
| |
| /** |
| * Returns whether or not [str] ends with [matcher]. |
| */ |
| bool endsWithPattern(String str, Pattern matcher) { |
| for (var match in matcher.allMatches(str)) { |
| if (match.end == str.length) return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the hex-encoded sha1 hash of [source]. |
| */ |
| String sha1(String source) => |
| CryptoUtils.bytesToHex(new SHA1().update(source.charCodes).digest()); |
| |
| /** |
| * Returns a [Future] that completes in [milliSeconds]. |
| */ |
| Future sleep(int milliSeconds) { |
| var completer = new Completer(); |
| new Timer(milliSeconds, completer.complete); |
| return completer.future; |
| } |