summaryrefslogtreecommitdiff
path: root/libphobos/libdruntime/core/time.d
diff options
context:
space:
mode:
Diffstat (limited to 'libphobos/libdruntime/core/time.d')
-rw-r--r--libphobos/libdruntime/core/time.d158
1 files changed, 94 insertions, 64 deletions
diff --git a/libphobos/libdruntime/core/time.d b/libphobos/libdruntime/core/time.d
index 0ddf62f478c..91f218e27fb 100644
--- a/libphobos/libdruntime/core/time.d
+++ b/libphobos/libdruntime/core/time.d
@@ -496,6 +496,81 @@ assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) ==
+/
struct Duration
{
+ /++
+ Converts this `Duration` to a `string`.
+
+ The string is meant to be human readable, not machine parseable (e.g.
+ whether there is an `'s'` on the end of the unit name usually depends on
+ whether it's plural or not, and empty units are not included unless the
+ Duration is `zero`). Any code needing a specific string format should
+ use `total` or `split` to get the units needed to create the desired
+ string format and create the string itself.
+
+ The format returned by toString may or may not change in the future.
+
+ Params:
+ sink = A sink object, expected to be a delegate or aggregate
+ implementing `opCall` that accepts a `scope const(char)[]`
+ as argument.
+ +/
+ void toString (SinkT) (scope SinkT sink) const scope
+ {
+ static immutable units = [
+ "weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs"
+ ];
+
+ static void appListSep(SinkT sink, uint pos, bool last)
+ {
+ if (pos == 0)
+ return;
+ if (!last)
+ sink(", ");
+ else
+ sink(pos == 1 ? " and " : ", and ");
+ }
+
+ static void appUnitVal(string units)(SinkT sink, long val)
+ {
+ immutable plural = val != 1;
+ string unit;
+ static if (units == "seconds")
+ unit = plural ? "secs" : "sec";
+ else static if (units == "msecs")
+ unit = "ms";
+ else static if (units == "usecs")
+ unit = "μs";
+ else
+ unit = plural ? units : units[0 .. $-1];
+ sink(signedToTempString(val));
+ sink(" ");
+ sink(unit);
+ }
+
+ if (_hnsecs == 0)
+ {
+ sink("0 hnsecs");
+ return;
+ }
+
+ long hnsecs = _hnsecs;
+ uint pos;
+ static foreach (unit; units)
+ {
+ if (auto val = splitUnitsFromHNSecs!unit(hnsecs))
+ {
+ appListSep(sink, pos++, hnsecs == 0);
+ appUnitVal!unit(sink, val);
+ }
+ if (hnsecs == 0)
+ return;
+ }
+ if (hnsecs != 0)
+ {
+ appListSep(sink, pos++, true);
+ appUnitVal!"hnsecs"(sink, hnsecs);
+ }
+ }
+
@safe pure:
public:
@@ -1539,71 +1614,12 @@ public:
}
}
-
- /++
- Converts this `Duration` to a `string`.
-
- The string is meant to be human readable, not machine parseable (e.g.
- whether there is an `'s'` on the end of the unit name usually depends on
- whether it's plural or not, and empty units are not included unless the
- Duration is `zero`). Any code needing a specific string format should
- use `total` or `split` to get the units needed to create the desired
- string format and create the string itself.
-
- The format returned by toString may or may not change in the future.
- +/
- string toString() const nothrow pure @safe
+ /// Ditto
+ string toString() const scope nothrow
{
- static void appListSep(ref string res, uint pos, bool last)
- {
- if (pos == 0)
- return;
- if (!last)
- res ~= ", ";
- else
- res ~= pos == 1 ? " and " : ", and ";
- }
-
- static void appUnitVal(string units)(ref string res, long val)
- {
- immutable plural = val != 1;
- string unit;
- static if (units == "seconds")
- unit = plural ? "secs" : "sec";
- else static if (units == "msecs")
- unit = "ms";
- else static if (units == "usecs")
- unit = "μs";
- else
- unit = plural ? units : units[0 .. $-1];
- res ~= signedToTempString(val);
- res ~= " ";
- res ~= unit;
- }
-
- if (_hnsecs == 0)
- return "0 hnsecs";
-
- template TT(T...) { alias T TT; }
- alias units = TT!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs");
-
- long hnsecs = _hnsecs; string res; uint pos;
- foreach (unit; units)
- {
- if (auto val = splitUnitsFromHNSecs!unit(hnsecs))
- {
- appListSep(res, pos++, hnsecs == 0);
- appUnitVal!unit(res, val);
- }
- if (hnsecs == 0)
- break;
- }
- if (hnsecs != 0)
- {
- appListSep(res, pos++, true);
- appUnitVal!"hnsecs"(res, hnsecs);
- }
- return res;
+ string result;
+ this.toString((in char[] data) { result ~= data; });
+ return result;
}
///
@@ -1731,6 +1747,20 @@ unittest
assert(myTime == 123.msecs);
}
+// Ensure `toString` doesn't allocate if the sink doesn't
+version (CoreUnittest) @safe pure nothrow @nogc unittest
+{
+ char[256] buffer; size_t len;
+ scope sink = (in char[] data) {
+ assert(data.length + len <= buffer.length);
+ buffer[len .. len + data.length] = data[];
+ len += data.length;
+ };
+ auto dur = Duration(-12_096_020_900_003);
+ dur.toString(sink);
+ assert(buffer[0 .. len] == "-2 weeks, -2 secs, -90 ms, and -3 hnsecs");
+}
+
/++
Converts a $(D TickDuration) to the given units as either an integral
value or a floating point value.