Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Treat division by 0 as an error in Duration and consolidate code.
Browse files Browse the repository at this point in the history
Duration should never have checked for division by 0 and thrown a
TimeException when it occurred. The OS/hardware already checks for that,
and it should be considered a logic error. Checking for it and possibly
throwing just slows the code down and makes it so that it can't be @nogc.

This is technically a breaking change, but it will only break code which
doesn't bother to avoid dividing by 0 and then catches TimeException
when it occurs, and such code is likely extremely rare, if it exists at
all. Given the fact that the odds of actually breaking code are
extremely low and that this allows us to make Duration fully @nogc except
for toString, I think that it's worth the risk.
  • Loading branch information
jmdavis committed Oct 10, 2015
1 parent 8ddfb8d commit 1a9e809
Showing 1 changed file with 28 additions and 99 deletions.
127 changes: 28 additions & 99 deletions src/core/time.d
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,6 @@ public:
return -1;
if(_hnsecs > rhs._hnsecs)
return 1;

return 0;
}

Expand Down Expand Up @@ -681,7 +680,6 @@ public:
mixin("_hnsecs " ~ op ~ "= rhs._hnsecs;");
else if(is(_Unqual!D == TickDuration))
mixin("_hnsecs " ~ op ~ "= rhs.hnsecs;");

return this;
}

Expand Down Expand Up @@ -770,26 +768,24 @@ public:
}


// Note: opBinary!"*" and opBinary!"/" have to be implemented separately
// because opBinary!"/" may throw TimeException, and opBinary!"*" is nothrow

/++
Multiplies the duration by an integer value.
Multiplies or divides the duration by an integer value.
The legal types of arithmetic for $(D Duration) using this operator
overload are
$(TABLE
$(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration))
$(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration))
)
Params:
value = The value to multiply this $(D Duration) by.
+/
Duration opBinary(string op)(long value) const nothrow @nogc
if(op == "*")
if(op == "*" || op == "/")
{
return Duration(_hnsecs * value);
mixin("return Duration(_hnsecs " ~ op ~ " value);");
}

unittest
Expand All @@ -813,27 +809,45 @@ public:
}
}

unittest
{
foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration))
{
assert((cast(D)Duration(5)) / 7 == Duration(0));
assert((cast(D)Duration(7)) / 5 == Duration(1));

assert((cast(D)Duration(5)) / -7 == Duration(0));
assert((cast(D)Duration(7)) / -5 == Duration(-1));

assert((cast(D)Duration(-5)) / 7 == Duration(0));
assert((cast(D)Duration(-7)) / 5 == Duration(-1));

assert((cast(D)Duration(-5)) / -7 == Duration(0));
assert((cast(D)Duration(-7)) / -5 == Duration(1));
}
}


/++
Multiplies the duration by an integer value as well as
Multiplies/Divides the duration by an integer value as well as
assigning the result to this $(D Duration).
The legal types of arithmetic for $(D Duration) using this operator
overload are
$(TABLE
$(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration))
$(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration))
)
Params:
value = The value to multiply this $(D Duration) by.
value = The value to multiply/divide this $(D Duration) by.
+/
ref Duration opOpAssign(string op)(long value) nothrow @nogc
if(op == "*")
if(op == "*" || op == "/")
{
_hnsecs *= value;

return this;
mixin("_hnsecs " ~ op ~ "= value;");
return this;
}

unittest
Expand Down Expand Up @@ -868,93 +882,8 @@ public:
static assert(!__traits(compiles, idur *= 12));
}


/++
Divides the duration by an integer value.
The legal types of arithmetic for $(D Duration) using this operator
overload are
$(TABLE
$(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration))
)
Params:
value = The value to divide from this duration.
Throws:
$(D TimeException) if an attempt to divide by $(D 0) is made.
+/
Duration opBinary(string op)(long value) const
if(op == "/")
{
if(value == 0)
throw new TimeException("Attempted division by 0.");

return Duration(_hnsecs / value);
}

unittest
{
//Unfortunately, putting these inside of the foreach loop results in
//linker errors regarding multiple definitions and the lambdas.
_assertThrown!TimeException((){Duration(5) / 0;}());
_assertThrown!TimeException((){Duration(-5) / 0;}());
_assertThrown!TimeException((){(cast(const Duration)Duration(5)) / 0;}());
_assertThrown!TimeException((){(cast(const Duration)Duration(-5)) / 0;}());
_assertThrown!TimeException((){(cast(immutable Duration)Duration(5)) / 0;}());
_assertThrown!TimeException((){(cast(immutable Duration)Duration(-5)) / 0;}());

foreach(D; _TypeTuple!(Duration, const Duration, immutable Duration))
{
assert((cast(D)Duration(5)) / 7 == Duration(0));
assert((cast(D)Duration(7)) / 5 == Duration(1));

assert((cast(D)Duration(5)) / -7 == Duration(0));
assert((cast(D)Duration(7)) / -5 == Duration(-1));

assert((cast(D)Duration(-5)) / 7 == Duration(0));
assert((cast(D)Duration(-7)) / 5 == Duration(-1));

assert((cast(D)Duration(-5)) / -7 == Duration(0));
assert((cast(D)Duration(-7)) / -5 == Duration(1));
}
}


/++
Divides the duration by an integer value as well as
assigning the result to this $(D Duration).
The legal types of arithmetic for $(D Duration) using this operator
overload are
$(TABLE
$(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration))
)
Params:
value = The value to divide from this $(D Duration).
Throws:
$(D TimeException) if an attempt to divide by $(D 0) is made.
+/
ref Duration opOpAssign(string op)(long value)
if(op == "/")
{
if(value == 0)
throw new TimeException("Attempted division by 0.");

_hnsecs /= value;

return this;
}

unittest
{
_assertThrown!TimeException((){Duration(5) /= 0;}());
_assertThrown!TimeException((){Duration(-5) /= 0;}());

static void test(Duration actual, long value, Duration expected, size_t line = __LINE__)
{
if((actual /= value) != expected)
Expand Down

0 comments on commit 1a9e809

Please sign in to comment.