Commit ae2bcc20 authored by Dominik Charousset's avatar Dominik Charousset

Fix several issues with new timestamps

parent 00aa2121
......@@ -47,6 +47,13 @@ constexpr timeout_definition_builder after(duration d) {
return {d};
}
/// Returns a generator for timeouts.
template <class Rep, class Period>
constexpr timeout_definition_builder
after(std::chrono::duration<Rep, Period> d) {
return after(duration{d});
}
} // namespace caf
#endif // CAF_AFTER_HPP
......@@ -402,15 +402,15 @@ public:
// always save/store durations as int64_t to work around possibly
// different integer types on different plattforms for standard typedefs
struct {
void operator()(duration_type& lhs, int64_t& rhs) const {
void operator()(duration_type& lhs, Rep& rhs) const {
duration_type tmp{rhs};
lhs = tmp;
}
void operator()(int64_t& lhs, duration_type& rhs) const {
void operator()(Rep& lhs, duration_type& rhs) const {
lhs = rhs.count();
}
} assign;
int64_t tmp;
Rep tmp;
return convert_apply(dref(), x, tmp, assign);
}
......
......@@ -33,41 +33,41 @@ namespace caf {
/// @relates duration
enum class time_unit : uint32_t {
invalid,
minutes,
seconds,
milliseconds,
microseconds
microseconds,
nanoseconds
};
/// Relates time_unit
std::string to_string(time_unit x);
// Calculates the index of a time_unit from the denominator of a ratio.
constexpr intmax_t denom_to_unit_index(intmax_t x, intmax_t offset = 2) {
return x < 1000 ? (x == 1 ? offset : 0)
: denom_to_unit_index(x / 1000, offset + 1);
}
constexpr time_unit denom_to_time_unit(intmax_t x) {
return static_cast<time_unit>(denom_to_unit_index(x));
}
/// Converts the ratio Num/Denom to a `time_unit` if the ratio describes
/// seconds, milliseconds, microseconds, or minutes. Minutes are mapped
/// to `time_unit::seconds`, any unrecognized ratio to `time_unit::invalid`.
/// @relates duration
template <intmax_t Num, intmax_t Denom>
struct ratio_to_time_unit_helper {
static constexpr time_unit value = time_unit::invalid;
};
struct ratio_to_time_unit_helper;
template <>
struct ratio_to_time_unit_helper<1, 1> {
static constexpr time_unit value = time_unit::seconds;
};
template <>
struct ratio_to_time_unit_helper<1, 1000> {
static constexpr time_unit value = time_unit::milliseconds;
};
template <>
struct ratio_to_time_unit_helper<1, 1000000> {
static constexpr time_unit value = time_unit::microseconds;
template <intmax_t Denom>
struct ratio_to_time_unit_helper<1, Denom> {
static constexpr time_unit value = denom_to_time_unit(Denom);
};
template <>
struct ratio_to_time_unit_helper<60, 1> {
static constexpr time_unit value = time_unit::seconds;
static constexpr time_unit value = time_unit::minutes;
};
/// Converts an STL time period to a `time_unit`.
......@@ -97,47 +97,37 @@ public:
// nop
}
constexpr duration(const infinite_t&) : unit(time_unit::invalid), count(0) {
constexpr duration(infinite_t) : unit(time_unit::invalid), count(0) {
// nop
}
/// Creates a new instance from an STL duration.
/// @throws std::invalid_argument Thrown if `d.count() is negative.
template <class Rep, class Period>
duration(std::chrono::duration<Rep, Period> d)
template <class Rep, class Period,
class E =
std::enable_if<
std::is_integral<Rep>::value
&& get_time_unit_from_period<Period>() != time_unit::invalid
>::type>
explicit duration(const std::chrono::duration<Rep, Period>& d)
: unit(get_time_unit_from_period<Period>()),
count(rd(d)) {
static_assert(get_time_unit_from_period<Period>() != time_unit::invalid,
"only minutes, seconds, milliseconds and "
"microseconds are supported");
static_assert(std::is_integral<Rep>::value,
"only integral durations are supported");
count(d.count() < 0 ? 0u : static_cast<uint64_t>(d.count())) {
// nop
}
/// Returns `unit != time_unit::invalid`.
inline bool valid() const {
constexpr bool valid() const {
return unit != time_unit::invalid;
}
/// Returns `count == 0`.
inline bool is_zero() const {
constexpr bool is_zero() const {
return count == 0;
}
time_unit unit;
uint64_t count;
private:
// reads d.count and throws invalid_argument if d.count < 0
template <class Rep, intmax_t Num, intmax_t D>
static uint64_t rd(const std::chrono::duration<Rep, std::ratio<Num, D>>& d) {
// assertion (via ctors): Num == 1 || (Num == 60 && D == 1)
// negative durations are not supported, map to 0
if (d.count() < 0)
return 0;
return static_cast<uint64_t>(d.count()) * static_cast<uint64_t>(Num);
}
};
/// @relates duration
......@@ -146,7 +136,7 @@ typename Inspector::result_type inspect(Inspector& f, duration& x) {
return f(x.unit, x.count);
}
/// @relates duration
std::string to_string(const duration& x);
/// @relates duration
......@@ -162,6 +152,11 @@ template <class Clock, class Duration>
std::chrono::time_point<Clock, Duration>&
operator+=(std::chrono::time_point<Clock, Duration>& lhs, const duration& rhs) {
switch (rhs.unit) {
case time_unit::invalid:
break;
case time_unit::minutes:
lhs += std::chrono::minutes(rhs.count);
break;
case time_unit::seconds:
lhs += std::chrono::seconds(rhs.count);
break;
......@@ -171,7 +166,8 @@ operator+=(std::chrono::time_point<Clock, Duration>& lhs, const duration& rhs) {
case time_unit::microseconds:
lhs += std::chrono::microseconds(rhs.count);
break;
case time_unit::invalid:
case time_unit::nanoseconds:
lhs += std::chrono::nanoseconds(rhs.count);
break;
}
return lhs;
......
......@@ -91,6 +91,25 @@ public:
}
return {req_id.response_id(), dptr};
}
/// Sends `{xs...}` as a synchronous message to `dest` with priority `mp`.
/// @returns A handle identifying a future-like handle to the response.
/// @warning The returned handle is actor specific and the response to the
/// sent message cannot be received by another actor.
template <message_priority P = message_priority::normal,
class Rep = int, class Period = std::ratio<1>,
class Handle = actor, class... Ts>
response_handle<Subtype,
response_type_t<
typename Handle::signatures,
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>,
is_blocking_requester<Subtype>::value>
request(const Handle& dest, std::chrono::duration<Rep, Period> timeout,
Ts&&... xs) {
return request(dest, duration{timeout}, std::forward<Ts>(xs)...);
}
};
} // namespace mixin
......
......@@ -143,6 +143,14 @@ public:
message_id::make(P), make_message(std::forward<Ts>(xs)...));
}
template <message_priority P = message_priority::normal,
class Rep = int, class Period = std::ratio<1>,
class Dest = actor, class... Ts>
void delayed_send(const Dest& dest, std::chrono::duration<Rep, Period> rtime,
Ts&&... xs) {
delayed_send(dest, duration{rtime}, std::forward<Ts>(xs)...);
}
template <message_priority P = message_priority::normal,
class Source = actor, class Dest = actor, class... Ts>
void delayed_anon_send(const Dest& dest, const duration& rtime, Ts&&... xs) {
......@@ -163,6 +171,15 @@ public:
make_message(std::forward<Ts>(xs)...));
}
template <message_priority P = message_priority::normal,
class Rep = int, class Period = std::ratio<1>,
class Source = actor, class Dest = actor, class... Ts>
void delayed_anon_send(const Dest& dest,
std::chrono::duration<Rep, Period> rtime,
Ts&&... xs) {
delayed_anon_send(dest, duration{rtime}, std::forward<Ts>(xs)...);
}
private:
Subtype* dptr() {
return static_cast<Subtype*>(this);
......
......@@ -29,16 +29,20 @@ namespace {
const char* time_unit_strings[] = {
"invalid",
"minutes",
"seconds",
"milliseconds",
"microseconds"
"microseconds",
"nanoseconds"
};
const char* time_unit_short_strings[] = {
"?",
"min",
"s",
"ms",
"us"
"us",
"ns"
};
} // namespace <anonymous>
......
......@@ -141,8 +141,8 @@ struct fixture {
int32_t i32 = -345;
float f32 = 3.45f;
double f64 = 54.3;
timestamp::duration dur = timestamp::duration{1478715821 * 1000000000ll};
timestamp ts = timestamp{dur};
duration dur = duration{time_unit::seconds, 123};
timestamp ts = timestamp{timestamp::duration{1478715821 * 1000000000ll}};
test_enum te = test_enum::b;
string str = "Lorem ipsum dolor sit amet.";
raw_struct rs;
......@@ -265,7 +265,7 @@ CAF_TEST(double_values) {
CAF_TEST(duration_values) {
auto buf = serialize(dur);
timestamp::duration x;
duration x;
deserialize(buf, x);
CAF_CHECK_EQUAL(dur, x);
}
......@@ -352,14 +352,14 @@ CAF_TEST(messages) {
auto buf1 = serialize(msg);
deserialize(buf1, x);
CAF_CHECK_EQUAL(to_string(msg), to_string(x));
CAF_CHECK(is_message(x).equal(i32, te, str, rs));
CAF_CHECK(is_message(x).equal(i32, dur, ts, te, str, rs));
// serialize fully dynamic message again (do another roundtrip)
message y;
auto buf2 = serialize(x);
CAF_CHECK_EQUAL(buf1, buf2);
deserialize(buf2, y);
CAF_CHECK_EQUAL(to_string(msg), to_string(y));
CAF_CHECK(is_message(y).equal(i32, te, str, rs));
CAF_CHECK(is_message(y).equal(i32, dur, ts, te, str, rs));
}
CAF_TEST(multiple_messages) {
......@@ -372,7 +372,7 @@ CAF_TEST(multiple_messages) {
CAF_CHECK_EQUAL(std::make_tuple(t, to_string(m1), to_string(m2)),
std::make_tuple(te, to_string(m), to_string(msg)));
CAF_CHECK(is_message(m1).equal(rs, te));
CAF_CHECK(is_message(m2).equal(i32, te, str, rs));
CAF_CHECK(is_message(m2).equal(i32, dur, ts, te, str, rs));
}
......
......@@ -81,6 +81,14 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(timeout_tests, fixture)
CAF_TEST(duration_conversion) {
duration d1{time_unit::milliseconds, 100};
std::chrono::milliseconds d2{100};
duration d3{d2};
CAF_CHECK_EQUAL(d1.count, d2.count());
CAF_CHECK_EQUAL(d1, d3);
}
CAF_TEST(single_timeout) {
system.spawn(timer_impl);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment