d6ceee805e
Bug: #51401 TEST=ci Change-Id: Idc680edc71bc0e6842f4539a9de2ed283ce7f0ef Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/283362 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Ben Konyi <bkonyi@google.com>
305 lines
8.6 KiB
Dart
305 lines
8.6 KiB
Dart
// Copyright (c) 2014, 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.
|
|
|
|
library utils;
|
|
|
|
import 'dart:async';
|
|
import 'dart:math';
|
|
|
|
enum DurationComponent {
|
|
Days,
|
|
Hours,
|
|
Minutes,
|
|
Seconds,
|
|
Milliseconds,
|
|
Microseconds
|
|
}
|
|
|
|
class Utils {
|
|
static String formatPercentNormalized(double x) {
|
|
var percent = 100.0 * x;
|
|
return '${percent.toStringAsFixed(2)}%';
|
|
}
|
|
|
|
static String formatPercent(num a, num total) {
|
|
return formatPercentNormalized(a / total);
|
|
}
|
|
|
|
static String zeroPad(int value, int pad) {
|
|
String prefix = "";
|
|
while (pad > 1) {
|
|
int pow10 = pow(10, pad - 1) as int;
|
|
if (value < pow10) {
|
|
prefix = prefix + "0";
|
|
}
|
|
pad--;
|
|
}
|
|
return "${prefix}${value}";
|
|
}
|
|
|
|
static String formatCommaSeparated(int v) {
|
|
const COMMA_EVERY = 1000;
|
|
if (v < COMMA_EVERY) {
|
|
return v.toString();
|
|
}
|
|
var mod = v % COMMA_EVERY;
|
|
v ~/= COMMA_EVERY;
|
|
var r = '${zeroPad(mod, 3)}';
|
|
while (v > COMMA_EVERY) {
|
|
mod = v % COMMA_EVERY;
|
|
r = '${zeroPad(mod, 3)},$r';
|
|
v ~/= COMMA_EVERY;
|
|
}
|
|
if (v != 0) {
|
|
r = '$v,$r';
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static String formatTimePrecise(double time) {
|
|
const millisPerSecond = 1000;
|
|
|
|
var millis = (time * millisPerSecond).round();
|
|
return formatTimeMilliseconds(millis);
|
|
}
|
|
|
|
static String formatTimeMilliseconds(int millis) {
|
|
const millisPerHour = 60 * 60 * 1000;
|
|
const millisPerMinute = 60 * 1000;
|
|
const millisPerSecond = 1000;
|
|
|
|
var hours = millis ~/ millisPerHour;
|
|
millis = millis % millisPerHour;
|
|
|
|
var minutes = millis ~/ millisPerMinute;
|
|
millis = millis % millisPerMinute;
|
|
|
|
var seconds = millis ~/ millisPerSecond;
|
|
millis = millis % millisPerSecond;
|
|
|
|
if (hours > 0) {
|
|
return ("${zeroPad(hours, 2)}"
|
|
":${zeroPad(minutes, 2)}"
|
|
":${zeroPad(seconds, 2)}"
|
|
".${zeroPad(millis, 3)}");
|
|
} else if (minutes > 0) {
|
|
return ("${zeroPad(minutes, 2)}"
|
|
":${zeroPad(seconds, 2)}"
|
|
".${zeroPad(millis, 3)}");
|
|
} else {
|
|
return ("${zeroPad(seconds, 2)}"
|
|
".${zeroPad(millis, 3)}");
|
|
}
|
|
}
|
|
|
|
static String formatSize(bytesDynamic) {
|
|
int bytes = bytesDynamic.toInt();
|
|
|
|
String finish(int scale, String prefix) {
|
|
double scaled = bytes / scale;
|
|
int digits = 1;
|
|
if (scaled < 10) digits = 2;
|
|
return "${scaled.toStringAsFixed(digits)}${prefix}B";
|
|
}
|
|
|
|
const int bytesPerKB = 1024;
|
|
const int bytesPerMB = 1024 * bytesPerKB;
|
|
const int bytesPerGB = 1024 * bytesPerMB;
|
|
const int bytesPerTB = 1024 * bytesPerGB;
|
|
|
|
int absBytes = bytes >= 0 ? bytes : -bytes;
|
|
if (absBytes < bytesPerKB) return "${bytes}B";
|
|
if (absBytes < bytesPerMB) return finish(bytesPerKB, "K");
|
|
if (absBytes < bytesPerGB) return finish(bytesPerMB, "M");
|
|
if (absBytes < bytesPerTB) return finish(bytesPerGB, "G");
|
|
return finish(bytesPerTB, "TB");
|
|
}
|
|
|
|
static String formatTime(double time) {
|
|
const millisPerHour = 60 * 60 * 1000;
|
|
const millisPerMinute = 60 * 1000;
|
|
const millisPerSecond = 1000;
|
|
|
|
var millis = (time * millisPerSecond).round();
|
|
|
|
var hours = millis ~/ millisPerHour;
|
|
millis = millis % millisPerHour;
|
|
|
|
var minutes = millis ~/ millisPerMinute;
|
|
millis = millis % millisPerMinute;
|
|
|
|
var seconds = millis ~/ millisPerSecond;
|
|
|
|
if (hours != 0) {
|
|
return '${hours}h ${minutes}m ${seconds}s';
|
|
}
|
|
if (minutes != 0) {
|
|
return '${minutes}m ${seconds}s';
|
|
}
|
|
return '${seconds}s';
|
|
}
|
|
|
|
static String formatDateTime(DateTime now) {
|
|
return '${now.year}-${now.month}-${now.day} '
|
|
'${now.hour.toString().padLeft(2)}:'
|
|
'${now.minute.toString().padLeft(2)}:'
|
|
'${now.second.toString().padLeft(2)}';
|
|
}
|
|
|
|
static String formatDuration(Duration duration,
|
|
{DurationComponent precision = DurationComponent.Microseconds,
|
|
String future = '',
|
|
String past = 'ago'}) {
|
|
var value = duration.inMicroseconds.abs();
|
|
switch (precision) {
|
|
case DurationComponent.Days:
|
|
value = (value / Duration.microsecondsPerDay).round();
|
|
break;
|
|
case DurationComponent.Hours:
|
|
value = (value / Duration.microsecondsPerHour).round();
|
|
break;
|
|
case DurationComponent.Minutes:
|
|
value = (value / Duration.microsecondsPerMinute).round();
|
|
break;
|
|
case DurationComponent.Seconds:
|
|
value = (value / Duration.microsecondsPerSecond).round();
|
|
break;
|
|
case DurationComponent.Milliseconds:
|
|
value = (value / Duration.microsecondsPerMillisecond).round();
|
|
break;
|
|
case DurationComponent.Microseconds:
|
|
break;
|
|
}
|
|
final components = <String>[];
|
|
if (duration.isNegative) {
|
|
if (!past.isEmpty) {
|
|
components.add(past);
|
|
}
|
|
} else {
|
|
if (!future.isEmpty) {
|
|
components.add(future);
|
|
}
|
|
}
|
|
switch (precision) {
|
|
case DurationComponent.Microseconds:
|
|
components.add('${value % Duration.microsecondsPerMillisecond}μs');
|
|
value = (value / Duration.microsecondsPerMillisecond).floor();
|
|
if (value != 0) {
|
|
continue Milliseconds;
|
|
}
|
|
break;
|
|
Milliseconds:
|
|
case DurationComponent.Milliseconds:
|
|
components.add('${value % Duration.millisecondsPerSecond}ms');
|
|
value = (value / Duration.millisecondsPerSecond).floor();
|
|
if (value != 0) {
|
|
continue Seconds;
|
|
}
|
|
break;
|
|
Seconds:
|
|
case DurationComponent.Seconds:
|
|
components.add('${value % Duration.secondsPerMinute}s');
|
|
value = (value / Duration.secondsPerMinute).floor();
|
|
;
|
|
if (value != 0) {
|
|
continue Minutes;
|
|
}
|
|
break;
|
|
Minutes:
|
|
case DurationComponent.Minutes:
|
|
components.add('${value % Duration.minutesPerHour}m');
|
|
value = (value / Duration.minutesPerHour).floor();
|
|
if (value != 0) {
|
|
continue Hours;
|
|
}
|
|
break;
|
|
Hours:
|
|
case DurationComponent.Hours:
|
|
components.add('${value % Duration.hoursPerDay}h');
|
|
value = (value / Duration.hoursPerDay).floor();
|
|
if (value != 0) {
|
|
continue Days;
|
|
}
|
|
break;
|
|
Days:
|
|
case DurationComponent.Days:
|
|
components.add('${value}d');
|
|
}
|
|
return components.reversed.join(' ');
|
|
}
|
|
|
|
static String formatSeconds(double x) {
|
|
return x.toStringAsFixed(2);
|
|
}
|
|
|
|
static String formatMillis(double x) {
|
|
return x.toStringAsFixed(2);
|
|
}
|
|
|
|
static String formatDurationInSeconds(Duration x) =>
|
|
formatSeconds(x.inMicroseconds / Duration.microsecondsPerSecond);
|
|
|
|
static String formatDurationInMilliseconds(Duration x) =>
|
|
formatMillis(x.inMicroseconds / Duration.microsecondsPerMillisecond);
|
|
|
|
static bool runningInJavaScript() => identical(1.0, 1);
|
|
|
|
static formatStringAsLiteral(String value, [bool wasTruncated = false]) {
|
|
var result = <int>[];
|
|
result.add("'".codeUnitAt(0));
|
|
for (int codeUnit in value.codeUnits) {
|
|
if (codeUnit == '\n'.codeUnitAt(0))
|
|
result.addAll('\\n'.codeUnits);
|
|
else if (codeUnit == '\r'.codeUnitAt(0))
|
|
result.addAll('\\r'.codeUnits);
|
|
else if (codeUnit == '\f'.codeUnitAt(0))
|
|
result.addAll('\\f'.codeUnits);
|
|
else if (codeUnit == '\b'.codeUnitAt(0))
|
|
result.addAll('\\b'.codeUnits);
|
|
else if (codeUnit == '\t'.codeUnitAt(0))
|
|
result.addAll('\\t'.codeUnits);
|
|
else if (codeUnit == '\v'.codeUnitAt(0))
|
|
result.addAll('\\v'.codeUnits);
|
|
else if (codeUnit == '\$'.codeUnitAt(0))
|
|
result.addAll('\\\$'.codeUnits);
|
|
else if (codeUnit == '\\'.codeUnitAt(0))
|
|
result.addAll('\\\\'.codeUnits);
|
|
else if (codeUnit == "'".codeUnitAt(0))
|
|
result.addAll("'".codeUnits);
|
|
else if (codeUnit < 32) {
|
|
var escapeSequence = "\\u" + codeUnit.toRadixString(16).padLeft(4, "0");
|
|
result.addAll(escapeSequence.codeUnits);
|
|
} else
|
|
result.add(codeUnit);
|
|
}
|
|
if (wasTruncated) {
|
|
result.addAll("...".codeUnits);
|
|
} else {
|
|
result.add("'".codeUnitAt(0));
|
|
}
|
|
return new String.fromCharCodes(result);
|
|
}
|
|
}
|
|
|
|
/// A [Task] that can be scheduled on the Dart event queue.
|
|
class Task {
|
|
Timer? _timer;
|
|
final Function callback;
|
|
|
|
Task(this.callback);
|
|
|
|
/// Queue [this] to run on the next Dart event queue pump. Does nothing
|
|
/// if [this] is already queued.
|
|
queue() {
|
|
if (_timer != null) {
|
|
// Already scheduled.
|
|
return;
|
|
}
|
|
_timer = new Timer(Duration.zero, () {
|
|
_timer = null;
|
|
callback();
|
|
});
|
|
}
|
|
}
|