Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 80 additions & 49 deletions include/msgpack/v1/adaptor/cpp11/chrono.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#include <chrono>

#include <boost/numeric/conversion/cast.hpp>

namespace msgpack {

/// @cond
Expand All @@ -25,13 +27,12 @@ MSGPACK_API_VERSION_NAMESPACE(v1) {

namespace adaptor {

template <typename Clock>
struct as<std::chrono::time_point<Clock>> {
typename std::chrono::time_point<Clock> operator()(msgpack::object const& o) const {
using duration_t = typename std::chrono::time_point<Clock>::duration;
template <typename Clock, typename Duration>
struct as<std::chrono::time_point<Clock, Duration>> {
typename std::chrono::time_point<Clock, Duration> operator()(msgpack::object const& o) const {
if(o.type != msgpack::type::EXT) { throw msgpack::type_error(); }
if(o.via.ext.type() != -1) { throw msgpack::type_error(); }
std::chrono::time_point<Clock> tp;
std::chrono::time_point<Clock, Duration> tp;
switch(o.via.ext.size) {
case 4: {
uint32_t sec;
Expand All @@ -41,9 +42,9 @@ struct as<std::chrono::time_point<Clock>> {
case 8: {
uint64_t value;
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
uint32_t nanosec = static_cast<uint32_t>(value >> 34);
uint32_t nanosec = boost::numeric_cast<uint32_t>(value >> 34);
uint64_t sec = value & 0x00000003ffffffffLL;
tp += std::chrono::duration_cast<duration_t>(
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(nanosec));
tp += std::chrono::seconds(sec);
} break;
Expand All @@ -52,9 +53,24 @@ struct as<std::chrono::time_point<Clock>> {
_msgpack_load32(uint32_t, o.via.ext.data(), &nanosec);
int64_t sec;
_msgpack_load64(int64_t, o.via.ext.data() + 4, &sec);
tp += std::chrono::duration_cast<duration_t>(
std::chrono::nanoseconds(nanosec));
tp += std::chrono::seconds(sec);

if (sec > 0) {
tp += std::chrono::seconds(sec);
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(nanosec));
}
else {
if (nanosec == 0) {
tp += std::chrono::seconds(sec);
}
else {
++sec;
tp += std::chrono::seconds(sec);
int64_t ns = boost::numeric_cast<int64_t>(nanosec) - 1000000000L;
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(ns));
}
}
} break;
default:
throw msgpack::type_error();
Expand All @@ -63,13 +79,12 @@ struct as<std::chrono::time_point<Clock>> {
}
};

template <typename Clock>
struct convert<std::chrono::time_point<Clock>> {
msgpack::object const& operator()(msgpack::object const& o, std::chrono::time_point<Clock>& v) const {
using duration_t = typename std::chrono::time_point<Clock>::duration;
template <typename Clock, typename Duration>
struct convert<std::chrono::time_point<Clock, Duration>> {
msgpack::object const& operator()(msgpack::object const& o, std::chrono::time_point<Clock, Duration>& v) const {
if(o.type != msgpack::type::EXT) { throw msgpack::type_error(); }
if(o.via.ext.type() != -1) { throw msgpack::type_error(); }
std::chrono::time_point<Clock> tp;
std::chrono::time_point<Clock, Duration> tp;
switch(o.via.ext.size) {
case 4: {
uint32_t sec;
Expand All @@ -80,9 +95,9 @@ struct convert<std::chrono::time_point<Clock>> {
case 8: {
uint64_t value;
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
uint32_t nanosec = static_cast<uint32_t>(value >> 34);
uint32_t nanosec = boost::numeric_cast<uint32_t>(value >> 34);
uint64_t sec = value & 0x00000003ffffffffLL;
tp += std::chrono::duration_cast<duration_t>(
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(nanosec));
tp += std::chrono::seconds(sec);
v = tp;
Expand All @@ -92,9 +107,25 @@ struct convert<std::chrono::time_point<Clock>> {
_msgpack_load32(uint32_t, o.via.ext.data(), &nanosec);
int64_t sec;
_msgpack_load64(int64_t, o.via.ext.data() + 4, &sec);
tp += std::chrono::duration_cast<duration_t>(
std::chrono::nanoseconds(nanosec));
tp += std::chrono::seconds(sec);

if (sec > 0) {
tp += std::chrono::seconds(sec);
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(nanosec));
}
else {
if (nanosec == 0) {
tp += std::chrono::seconds(sec);
}
else {
++sec;
tp += std::chrono::seconds(sec);
int64_t ns = boost::numeric_cast<int64_t>(nanosec) - 1000000000L;
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(ns));
}
}

v = tp;
} break;
default:
Expand All @@ -104,32 +135,31 @@ struct convert<std::chrono::time_point<Clock>> {
}
};

template <typename Clock>
struct pack<std::chrono::time_point<Clock>> {
template <typename Clock, typename Duration>
struct pack<std::chrono::time_point<Clock, Duration>> {
template <typename Stream>
msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, std::chrono::time_point<Clock> const& v) const {
using duration_t = typename std::chrono::time_point<Clock>::duration;
int64_t count = static_cast<int64_t>(v.time_since_epoch().count());

msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, std::chrono::time_point<Clock, Duration> const& v) const {
int64_t count = boost::numeric_cast<int64_t>(v.time_since_epoch().count());
int64_t nano_num =
duration_t::period::ratio::num *
(1000000000 / duration_t::period::ratio::den);
Duration::period::ratio::num *
(1000000000L / Duration::period::ratio::den);

int64_t nanosec = count % (1000000000 / nano_num) * nano_num;
int64_t nanosec = count % (1000000000L / nano_num) * nano_num;
int64_t sec = 0;
if (nanosec < 0) {
nanosec = 1000000000 + nanosec;
nanosec = 1000000000L + nanosec;
--sec;
}
sec += count
* duration_t::period::ratio::num
/ duration_t::period::ratio::den;
* Duration::period::ratio::num
/ Duration::period::ratio::den;

if ((sec >> 34) == 0) {
uint64_t data64 = (static_cast<uint64_t>(nanosec) << 34) | static_cast<uint64_t>(sec);
uint64_t data64 = (boost::numeric_cast<uint64_t>(nanosec) << 34) | boost::numeric_cast<uint64_t>(sec);
if ((data64 & 0xffffffff00000000L) == 0) {
// timestamp 32
o.pack_ext(4, -1);
uint32_t data32 = static_cast<uint32_t>(data64);
uint32_t data32 = boost::numeric_cast<uint32_t>(data64);
char buf[4];
_msgpack_store32(buf, data32);
o.pack_ext_body(buf, 4);
Expand All @@ -146,42 +176,43 @@ struct pack<std::chrono::time_point<Clock>> {
// timestamp 96
o.pack_ext(12, -1);
char buf[12];
_msgpack_store32(&buf[0], static_cast<uint32_t>(nanosec));


_msgpack_store32(&buf[0], boost::numeric_cast<uint32_t>(nanosec));
_msgpack_store64(&buf[4], sec);
o.pack_ext_body(buf, 12);
}
return o;
}
};

template <typename Clock>
struct object_with_zone<std::chrono::time_point<Clock>> {
void operator()(msgpack::object::with_zone& o, const std::chrono::time_point<Clock>& v) const {
using duration_t = typename std::chrono::time_point<Clock>::duration;
int64_t count = static_cast<int64_t>(v.time_since_epoch().count());
template <typename Clock, typename Duration>
struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
void operator()(msgpack::object::with_zone& o, const std::chrono::time_point<Clock, Duration>& v) const {
int64_t count = boost::numeric_cast<int64_t>(v.time_since_epoch().count());

int64_t nano_num =
duration_t::period::ratio::num *
(1000000000 / duration_t::period::ratio::den);
Duration::period::ratio::num *
(1000000000L / Duration::period::ratio::den);

int64_t nanosec = count % (1000000000 / nano_num) * nano_num;
int64_t nanosec = count % (1000000000L / nano_num) * nano_num;
int64_t sec = 0;
if (nanosec < 0) {
nanosec = 1000000000 + nanosec;
nanosec = 1000000000L + nanosec;
--sec;
}
sec += count
* duration_t::period::ratio::num
/ duration_t::period::ratio::den;
* Duration::period::ratio::num
/ Duration::period::ratio::den;
if ((sec >> 34) == 0) {
uint64_t data64 = (static_cast<uint64_t>(nanosec) << 34) | static_cast<uint64_t>(sec);
uint64_t data64 = (boost::numeric_cast<uint64_t>(nanosec) << 34) | boost::numeric_cast<uint64_t>(sec);
if ((data64 & 0xffffffff00000000L) == 0) {
// timestamp 32
o.type = msgpack::type::EXT;
o.via.ext.size = 4;
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
p[0] = static_cast<char>(-1);
uint32_t data32 = static_cast<uint32_t>(data64);
uint32_t data32 = boost::numeric_cast<uint32_t>(data64);
_msgpack_store32(&p[1], data32);
o.via.ext.ptr = p;
}
Expand All @@ -201,7 +232,7 @@ struct object_with_zone<std::chrono::time_point<Clock>> {
o.via.ext.size = 12;
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
p[0] = static_cast<char>(-1);
_msgpack_store32(&p[1], static_cast<uint32_t>(nanosec));
_msgpack_store32(&p[1], boost::numeric_cast<uint32_t>(nanosec));
_msgpack_store64(&p[1 + 4], sec);
o.via.ext.ptr = p;
}
Expand Down