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) { ...@@ -47,6 +47,13 @@ constexpr timeout_definition_builder after(duration d) {
return {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 } // namespace caf
#endif // CAF_AFTER_HPP #endif // CAF_AFTER_HPP
...@@ -402,15 +402,15 @@ public: ...@@ -402,15 +402,15 @@ public:
// always save/store durations as int64_t to work around possibly // always save/store durations as int64_t to work around possibly
// different integer types on different plattforms for standard typedefs // different integer types on different plattforms for standard typedefs
struct { struct {
void operator()(duration_type& lhs, int64_t& rhs) const { void operator()(duration_type& lhs, Rep& rhs) const {
duration_type tmp{rhs}; duration_type tmp{rhs};
lhs = tmp; lhs = tmp;
} }
void operator()(int64_t& lhs, duration_type& rhs) const { void operator()(Rep& lhs, duration_type& rhs) const {
lhs = rhs.count(); lhs = rhs.count();
} }
} assign; } assign;
int64_t tmp; Rep tmp;
return convert_apply(dref(), x, tmp, assign); return convert_apply(dref(), x, tmp, assign);
} }
......
...@@ -33,41 +33,41 @@ namespace caf { ...@@ -33,41 +33,41 @@ namespace caf {
/// @relates duration /// @relates duration
enum class time_unit : uint32_t { enum class time_unit : uint32_t {
invalid, invalid,
minutes,
seconds, seconds,
milliseconds, milliseconds,
microseconds microseconds,
nanoseconds
}; };
/// Relates time_unit /// Relates time_unit
std::string to_string(time_unit x); 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 /// Converts the ratio Num/Denom to a `time_unit` if the ratio describes
/// seconds, milliseconds, microseconds, or minutes. Minutes are mapped /// seconds, milliseconds, microseconds, or minutes. Minutes are mapped
/// to `time_unit::seconds`, any unrecognized ratio to `time_unit::invalid`. /// to `time_unit::seconds`, any unrecognized ratio to `time_unit::invalid`.
/// @relates duration /// @relates duration
template <intmax_t Num, intmax_t Denom> template <intmax_t Num, intmax_t Denom>
struct ratio_to_time_unit_helper { struct ratio_to_time_unit_helper;
static constexpr time_unit value = time_unit::invalid;
};
template <> template <intmax_t Denom>
struct ratio_to_time_unit_helper<1, 1> { struct ratio_to_time_unit_helper<1, Denom> {
static constexpr time_unit value = time_unit::seconds; static constexpr time_unit value = denom_to_time_unit(Denom);
};
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 <> template <>
struct ratio_to_time_unit_helper<60, 1> { 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`. /// Converts an STL time period to a `time_unit`.
...@@ -97,47 +97,37 @@ public: ...@@ -97,47 +97,37 @@ public:
// nop // nop
} }
constexpr duration(const infinite_t&) : unit(time_unit::invalid), count(0) { constexpr duration(infinite_t) : unit(time_unit::invalid), count(0) {
// nop // nop
} }
/// Creates a new instance from an STL duration. /// Creates a new instance from an STL duration.
/// @throws std::invalid_argument Thrown if `d.count() is negative. /// @throws std::invalid_argument Thrown if `d.count() is negative.
template <class Rep, class Period> template <class Rep, class Period,
duration(std::chrono::duration<Rep, Period> d) 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>()), : unit(get_time_unit_from_period<Period>()),
count(rd(d)) { count(d.count() < 0 ? 0u : static_cast<uint64_t>(d.count())) {
static_assert(get_time_unit_from_period<Period>() != time_unit::invalid, // nop
"only minutes, seconds, milliseconds and "
"microseconds are supported");
static_assert(std::is_integral<Rep>::value,
"only integral durations are supported");
} }
/// Returns `unit != time_unit::invalid`. /// Returns `unit != time_unit::invalid`.
inline bool valid() const { constexpr bool valid() const {
return unit != time_unit::invalid; return unit != time_unit::invalid;
} }
/// Returns `count == 0`. /// Returns `count == 0`.
inline bool is_zero() const { constexpr bool is_zero() const {
return count == 0; return count == 0;
} }
time_unit unit; time_unit unit;
uint64_t count; 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 /// @relates duration
...@@ -146,7 +136,7 @@ typename Inspector::result_type inspect(Inspector& f, duration& x) { ...@@ -146,7 +136,7 @@ typename Inspector::result_type inspect(Inspector& f, duration& x) {
return f(x.unit, x.count); return f(x.unit, x.count);
} }
/// @relates duration
std::string to_string(const duration& x); std::string to_string(const duration& x);
/// @relates duration /// @relates duration
...@@ -162,6 +152,11 @@ template <class Clock, class Duration> ...@@ -162,6 +152,11 @@ template <class Clock, class Duration>
std::chrono::time_point<Clock, Duration>& std::chrono::time_point<Clock, Duration>&
operator+=(std::chrono::time_point<Clock, Duration>& lhs, const duration& rhs) { operator+=(std::chrono::time_point<Clock, Duration>& lhs, const duration& rhs) {
switch (rhs.unit) { switch (rhs.unit) {
case time_unit::invalid:
break;
case time_unit::minutes:
lhs += std::chrono::minutes(rhs.count);
break;
case time_unit::seconds: case time_unit::seconds:
lhs += std::chrono::seconds(rhs.count); lhs += std::chrono::seconds(rhs.count);
break; break;
...@@ -171,7 +166,8 @@ operator+=(std::chrono::time_point<Clock, Duration>& lhs, const duration& rhs) { ...@@ -171,7 +166,8 @@ operator+=(std::chrono::time_point<Clock, Duration>& lhs, const duration& rhs) {
case time_unit::microseconds: case time_unit::microseconds:
lhs += std::chrono::microseconds(rhs.count); lhs += std::chrono::microseconds(rhs.count);
break; break;
case time_unit::invalid: case time_unit::nanoseconds:
lhs += std::chrono::nanoseconds(rhs.count);
break; break;
} }
return lhs; return lhs;
......
...@@ -91,6 +91,25 @@ public: ...@@ -91,6 +91,25 @@ public:
} }
return {req_id.response_id(), dptr}; 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 } // namespace mixin
......
...@@ -143,6 +143,14 @@ public: ...@@ -143,6 +143,14 @@ public:
message_id::make(P), make_message(std::forward<Ts>(xs)...)); 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, template <message_priority P = message_priority::normal,
class Source = actor, class Dest = actor, class... Ts> class Source = actor, class Dest = actor, class... Ts>
void delayed_anon_send(const Dest& dest, const duration& rtime, Ts&&... xs) { void delayed_anon_send(const Dest& dest, const duration& rtime, Ts&&... xs) {
...@@ -163,6 +171,15 @@ public: ...@@ -163,6 +171,15 @@ public:
make_message(std::forward<Ts>(xs)...)); 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: private:
Subtype* dptr() { Subtype* dptr() {
return static_cast<Subtype*>(this); return static_cast<Subtype*>(this);
......
...@@ -29,16 +29,20 @@ namespace { ...@@ -29,16 +29,20 @@ namespace {
const char* time_unit_strings[] = { const char* time_unit_strings[] = {
"invalid", "invalid",
"minutes",
"seconds", "seconds",
"milliseconds", "milliseconds",
"microseconds" "microseconds",
"nanoseconds"
}; };
const char* time_unit_short_strings[] = { const char* time_unit_short_strings[] = {
"?", "?",
"min",
"s", "s",
"ms", "ms",
"us" "us",
"ns"
}; };
} // namespace <anonymous> } // namespace <anonymous>
......
...@@ -141,8 +141,8 @@ struct fixture { ...@@ -141,8 +141,8 @@ struct fixture {
int32_t i32 = -345; int32_t i32 = -345;
float f32 = 3.45f; float f32 = 3.45f;
double f64 = 54.3; double f64 = 54.3;
timestamp::duration dur = timestamp::duration{1478715821 * 1000000000ll}; duration dur = duration{time_unit::seconds, 123};
timestamp ts = timestamp{dur}; timestamp ts = timestamp{timestamp::duration{1478715821 * 1000000000ll}};
test_enum te = test_enum::b; test_enum te = test_enum::b;
string str = "Lorem ipsum dolor sit amet."; string str = "Lorem ipsum dolor sit amet.";
raw_struct rs; raw_struct rs;
...@@ -265,7 +265,7 @@ CAF_TEST(double_values) { ...@@ -265,7 +265,7 @@ CAF_TEST(double_values) {
CAF_TEST(duration_values) { CAF_TEST(duration_values) {
auto buf = serialize(dur); auto buf = serialize(dur);
timestamp::duration x; duration x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(dur, x); CAF_CHECK_EQUAL(dur, x);
} }
...@@ -352,14 +352,14 @@ CAF_TEST(messages) { ...@@ -352,14 +352,14 @@ CAF_TEST(messages) {
auto buf1 = serialize(msg); auto buf1 = serialize(msg);
deserialize(buf1, x); deserialize(buf1, x);
CAF_CHECK_EQUAL(to_string(msg), to_string(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) // serialize fully dynamic message again (do another roundtrip)
message y; message y;
auto buf2 = serialize(x); auto buf2 = serialize(x);
CAF_CHECK_EQUAL(buf1, buf2); CAF_CHECK_EQUAL(buf1, buf2);
deserialize(buf2, y); deserialize(buf2, y);
CAF_CHECK_EQUAL(to_string(msg), to_string(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) { CAF_TEST(multiple_messages) {
...@@ -372,7 +372,7 @@ 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)), CAF_CHECK_EQUAL(std::make_tuple(t, to_string(m1), to_string(m2)),
std::make_tuple(te, to_string(m), to_string(msg))); std::make_tuple(te, to_string(m), to_string(msg)));
CAF_CHECK(is_message(m1).equal(rs, te)); 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 { ...@@ -81,6 +81,14 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(timeout_tests, 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) { CAF_TEST(single_timeout) {
system.spawn(timer_impl); 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