Implemented #638.

Added Time Stamp support.
This commit is contained in:
Takatoshi Kondo
2017-10-23 08:42:48 +09:00
parent 0a65c443a2
commit cb2dcb19b9
6 changed files with 486 additions and 0 deletions

View File

@@ -173,6 +173,7 @@ IF (MSGPACK_ENABLE_CXX)
include/msgpack/adaptor/cpp11/array.hpp
include/msgpack/adaptor/cpp11/array_char.hpp
include/msgpack/adaptor/cpp11/array_unsigned_char.hpp
include/msgpack/adaptor/cpp11/chrono.hpp
include/msgpack/adaptor/cpp11/forward_list.hpp
include/msgpack/adaptor/cpp11/reference_wrapper.hpp
include/msgpack/adaptor/cpp11/shared_ptr.hpp
@@ -529,6 +530,7 @@ IF (MSGPACK_ENABLE_CXX)
include/msgpack/v1/adaptor/cpp11/array.hpp
include/msgpack/v1/adaptor/cpp11/array_char.hpp
include/msgpack/v1/adaptor/cpp11/array_unsigned_char.hpp
include/msgpack/v1/adaptor/cpp11/chrono.hpp
include/msgpack/v1/adaptor/cpp11/forward_list.hpp
include/msgpack/v1/adaptor/cpp11/reference_wrapper.hpp
include/msgpack/v1/adaptor/cpp11/shared_ptr.hpp

View File

@@ -0,0 +1,16 @@
//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2017 KONDO Takatoshi
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef MSGPACK_TYPE_CPP11_CHRONO_HPP
#define MSGPACK_TYPE_CPP11_CHRONO_HPP
#include "msgpack/v1/adaptor/cpp11/chrono.hpp"
#endif // MSGPACK_TYPE_CPP11_CHRONO_HPP

View File

@@ -34,6 +34,7 @@
#include "adaptor/cpp11/array.hpp"
#include "adaptor/cpp11/array_char.hpp"
#include "adaptor/cpp11/array_unsigned_char.hpp"
#include "adaptor/cpp11/chrono.hpp"
#include "adaptor/cpp11/forward_list.hpp"
#include "adaptor/cpp11/reference_wrapper.hpp"
#include "adaptor/cpp11/shared_ptr.hpp"

View File

@@ -0,0 +1,215 @@
//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2017 KONDO Takatoshi
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
#define MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
#include "msgpack/versioning.hpp"
#include "msgpack/adaptor/adaptor_base.hpp"
#include "msgpack/adaptor/check_container_size.hpp"
#include <chrono>
namespace msgpack {
/// @cond
MSGPACK_API_VERSION_NAMESPACE(v1) {
/// @endcond
namespace adaptor {
template <>
struct as<std::chrono::system_clock::time_point> {
typename std::chrono::system_clock::time_point 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::system_clock::time_point tp;
switch(o.via.ext.size) {
case 4: {
uint32_t sec;
_msgpack_load32(uint32_t, o.via.ext.data(), &sec);
tp += std::chrono::seconds(sec);
} break;
case 8: {
uint64_t value;
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
uint32_t nanosec = static_cast<uint32_t>(value >> 34);
uint64_t sec = value & 0x00000003ffffffffL;
tp += std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(nanosec));
tp += std::chrono::seconds(sec);
} break;
case 12: {
uint32_t nanosec;
_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<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(nanosec));
tp += std::chrono::seconds(sec);
} break;
default:
throw msgpack::type_error();
}
return tp;
}
};
template <>
struct convert<std::chrono::system_clock::time_point> {
msgpack::object const& operator()(msgpack::object const& o, std::chrono::system_clock::time_point& v) const {
if(o.type != msgpack::type::EXT) { throw msgpack::type_error(); }
if(o.via.ext.type() != -1) { throw msgpack::type_error(); }
std::chrono::system_clock::time_point tp;
switch(o.via.ext.size) {
case 4: {
uint32_t sec;
_msgpack_load32(uint32_t, o.via.ext.data(), &sec);
tp += std::chrono::seconds(sec);
v = tp;
} break;
case 8: {
uint64_t value;
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
uint32_t nanosec = static_cast<uint32_t>(value >> 34);
uint64_t sec = value & 0x00000003ffffffffL;
tp += std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(nanosec));
tp += std::chrono::seconds(sec);
v = tp;
} break;
case 12: {
uint32_t nanosec;
_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<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(nanosec));
tp += std::chrono::seconds(sec);
v = tp;
} break;
default:
throw msgpack::type_error();
}
return o;
}
};
template <>
struct pack<std::chrono::system_clock::time_point> {
template <typename Stream>
msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const std::chrono::system_clock::time_point& v) const {
int64_t count = static_cast<int64_t>(v.time_since_epoch().count());
int64_t nano_num =
std::chrono::system_clock::duration::period::ratio::num *
(1000000000 / std::chrono::system_clock::duration::period::ratio::den);
int64_t nanosec = count % (1000000000 / nano_num) * nano_num;
int64_t sec = 0;
if (nanosec < 0) {
nanosec = 1000000000 + nanosec;
--sec;
}
sec += count
* std::chrono::system_clock::duration::period::ratio::num
/ std::chrono::system_clock::duration::period::ratio::den;
if ((sec >> 34) == 0) {
uint64_t data64 = (nanosec << 34) | sec;
if ((data64 & 0xffffffff00000000L) == 0) {
// timestamp 32
o.pack_ext(4, -1);
uint32_t data32 = static_cast<uint32_t>(data64);
char buf[4];
_msgpack_store32(buf, data32);
o.pack_ext_body(buf, 4);
}
else {
// timestamp 64
o.pack_ext(8, -1);
char buf[8];
_msgpack_store64(buf, data64);
o.pack_ext_body(buf, 8);
}
}
else {
// timestamp 96
o.pack_ext(12, -1);
char buf[12];
_msgpack_store32(&buf[0], static_cast<uint32_t>(nanosec));
_msgpack_store64(&buf[4], sec);
o.pack_ext_body(buf, 12);
}
return o;
}
};
template <>
struct object_with_zone<std::chrono::system_clock::time_point> {
void operator()(msgpack::object::with_zone& o, const std::chrono::system_clock::time_point& v) const {
int64_t count = static_cast<int64_t>(v.time_since_epoch().count());
int64_t nano_num =
std::chrono::system_clock::duration::period::ratio::num *
(1000000000 / std::chrono::system_clock::duration::period::ratio::den);
int64_t nanosec = count % (1000000000 / nano_num) * nano_num;
int64_t sec = 0;
if (nanosec < 0) {
nanosec = 1000000000 + nanosec;
--sec;
}
sec += count
* std::chrono::system_clock::duration::period::ratio::num
/ std::chrono::system_clock::duration::period::ratio::den;
if ((sec >> 34) == 0) {
uint64_t data64 = (nanosec << 34) | 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] = -1;
uint32_t data32 = static_cast<uint32_t>(data64);
_msgpack_store32(&p[1], data32);
o.via.ext.ptr = p;
}
else {
// timestamp 64
o.type = msgpack::type::EXT;
o.via.ext.size = 8;
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
p[0] = -1;
_msgpack_store64(&p[1], data64);
o.via.ext.ptr = p;
}
}
else {
// timestamp 96
o.type = msgpack::type::EXT;
o.via.ext.size = 12;
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
p[0] = -1;
_msgpack_store32(&p[1], static_cast<uint32_t>(nanosec));
_msgpack_store64(&p[1 + 4], sec);
o.via.ext.ptr = p;
}
}
};
} // namespace adaptor
/// @cond
} // MSGPACK_API_VERSION_NAMESPACE(v1)
/// @endcond
} // namespace msgpack
#endif // MSGPACK_V1_TYPE_CPP11_CHRONO_HPP

View File

@@ -856,4 +856,192 @@ TEST(MSGPACK_NO_DEF_CON_ARRAY, simple_buffer)
EXPECT_EQ(val1, val2);
}
TEST(MSGPACK_CHRONO, system_clock)
{
std::chrono::system_clock::time_point val1;
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, val1);
msgpack::object_handle oh =
msgpack::unpack(sbuf.data(), sbuf.size());
std::chrono::system_clock::time_point val2 = oh.get().as<std::chrono::system_clock::time_point>();
EXPECT_EQ(val1, val2);
std::chrono::system_clock::time_point val3;
oh.get().convert(val3);
EXPECT_EQ(val1, val3);
}
TEST(MSGPACK_CHRONO, system_clock_32)
{
std::chrono::system_clock::time_point val1(std::chrono::seconds(0x12345678L));
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, val1);
char packed[] = {
static_cast<char>(0xd6),
static_cast<char>(-1),
static_cast<char>(0x12),
static_cast<char>(0x34),
static_cast<char>(0x56),
static_cast<char>(0x78)
};
EXPECT_EQ(memcmp(sbuf.data(), packed, sizeof(packed)), 0);
msgpack::object_handle oh =
msgpack::unpack(sbuf.data(), sbuf.size());
std::chrono::system_clock::time_point val2 = oh.get().as<std::chrono::system_clock::time_point>();
EXPECT_EQ(val1, val2);
std::chrono::system_clock::time_point val3;
oh.get().convert(val3);
EXPECT_EQ(val1, val3);
}
TEST(MSGPACK_CHRONO, system_clock_32_max)
{
std::chrono::system_clock::time_point val1(std::chrono::seconds(0xffffffffL));
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, val1);
char packed[] = {
static_cast<char>(0xd6),
static_cast<char>(-1),
static_cast<char>(0xff),
static_cast<char>(0xff),
static_cast<char>(0xff),
static_cast<char>(0xff)
};
EXPECT_EQ(memcmp(sbuf.data(), packed, sizeof(packed)), 0);
msgpack::object_handle oh =
msgpack::unpack(sbuf.data(), sbuf.size());
std::chrono::system_clock::time_point val2 = oh.get().as<std::chrono::system_clock::time_point>();
EXPECT_EQ(val1, val2);
std::chrono::system_clock::time_point val3;
oh.get().convert(val3);
EXPECT_EQ(val1, val3);
}
TEST(MSGPACK_CHRONO, system_clock_64)
{
std::chrono::system_clock::time_point val1(std::chrono::seconds(0x31234567L));
val1 +=
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(0x312345678L)
);
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, val1);
msgpack::object_handle oh =
msgpack::unpack(sbuf.data(), sbuf.size());
std::chrono::system_clock::time_point val2 = oh.get().as<std::chrono::system_clock::time_point>();
EXPECT_EQ(val1, val2);
std::chrono::system_clock::time_point val3;
oh.get().convert(val3);
EXPECT_EQ(val1, val3);
}
TEST(MSGPACK_CHRONO, system_clock_64_max)
{
std::chrono::system_clock::time_point val1(std::chrono::seconds(0xffffffffL));
val1 +=
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(0x3b9ac9ffL) // 999,999,999
);
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, val1);
char packed_nano[] = {
static_cast<char>(0xd7),
static_cast<char>(-1),
static_cast<char>(0xee), // 999,999,999 << 2
static_cast<char>(0x6b),
static_cast<char>(0x27),
static_cast<char>(0xfc),
static_cast<char>(0xff), // 32 bit sec
static_cast<char>(0xff),
static_cast<char>(0xff),
static_cast<char>(0xff)
};
char packed_micro[] = {
static_cast<char>(0xd7),
static_cast<char>(-1),
static_cast<char>(0xee), // 999,999,000 << 2
static_cast<char>(0x6b),
static_cast<char>(0x18),
static_cast<char>(0x60),
static_cast<char>(0xff), // 32 bit sec
static_cast<char>(0xff),
static_cast<char>(0xff),
static_cast<char>(0xff)
};
if (std::chrono::system_clock::duration::period::ratio::den == 1000000000) {
EXPECT_EQ(memcmp(sbuf.data(), packed_nano, sizeof(packed_nano)), 0);
}
else if (std::chrono::system_clock::duration::period::ratio::den == 1000000) {
EXPECT_EQ(memcmp(sbuf.data(), packed_micro, sizeof(packed_micro)), 0);
}
msgpack::object_handle oh =
msgpack::unpack(sbuf.data(), sbuf.size());
std::chrono::system_clock::time_point val2 = oh.get().as<std::chrono::system_clock::time_point>();
EXPECT_EQ(val1, val2);
std::chrono::system_clock::time_point val3;
oh.get().convert(val3);
EXPECT_EQ(val1, val3);
}
TEST(MSGPACK_CHRONO, system_clock_impl_min)
{
std::chrono::system_clock::time_point val1(std::chrono::system_clock::time_point::min());
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, val1);
msgpack::object_handle oh =
msgpack::unpack(sbuf.data(), sbuf.size());
std::chrono::system_clock::time_point val2 = oh.get().as<std::chrono::system_clock::time_point>();
EXPECT_EQ(val1, val2);
std::chrono::system_clock::time_point val3;
oh.get().convert(val3);
EXPECT_EQ(val1, val3);
}
TEST(MSGPACK_CHRONO, system_clock_impl_max)
{
std::chrono::system_clock::time_point val1(std::chrono::system_clock::time_point::max());
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, val1);
msgpack::object_handle oh =
msgpack::unpack(sbuf.data(), sbuf.size());
std::chrono::system_clock::time_point val2 = oh.get().as<std::chrono::system_clock::time_point>();
EXPECT_EQ(val1, val2);
std::chrono::system_clock::time_point val3;
oh.get().convert(val3);
EXPECT_EQ(val1, val3);
}
TEST(MSGPACK_CHRONO, system_clock_impl_now)
{
std::chrono::system_clock::time_point val1(std::chrono::system_clock::now());
msgpack::sbuffer sbuf;
msgpack::pack(sbuf, val1);
msgpack::object_handle oh =
msgpack::unpack(sbuf.data(), sbuf.size());
std::chrono::system_clock::time_point val2 = oh.get().as<std::chrono::system_clock::time_point>();
EXPECT_EQ(val1, val2);
std::chrono::system_clock::time_point val3;
oh.get().convert(val3);
EXPECT_EQ(val1, val3);
}
#endif // !defined(MSGPACK_USE_CPP03)

View File

@@ -953,6 +953,70 @@ TEST(object_with_zone, tuple_empty)
EXPECT_TRUE(obj.as<test_t>() == v);
}
TEST(object_with_zone, system_clock)
{
std::chrono::system_clock::time_point v;
msgpack::zone z;
msgpack::object obj(v, z);
EXPECT_TRUE(obj.as<std::chrono::system_clock::time_point>() == v);
}
TEST(object_with_zone, system_clock_32)
{
std::chrono::system_clock::time_point v(std::chrono::seconds(0x12345678L));
msgpack::zone z;
msgpack::object obj(v, z);
EXPECT_TRUE(obj.as<std::chrono::system_clock::time_point>() == v);
}
TEST(object_with_zone, system_clock_32_max)
{
std::chrono::system_clock::time_point v(std::chrono::seconds(0xffffffffL));
msgpack::zone z;
msgpack::object obj(v, z);
EXPECT_TRUE(obj.as<std::chrono::system_clock::time_point>() == v);
}
TEST(object_with_zone, system_clock_64)
{
std::chrono::system_clock::time_point v(std::chrono::seconds(0x31234567L));
v +=
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(0x312345678L)
);
msgpack::zone z;
msgpack::object obj(v, z);
EXPECT_TRUE(obj.as<std::chrono::system_clock::time_point>() == v);
}
TEST(object_with_zone, system_clock_64_max)
{
std::chrono::system_clock::time_point v(std::chrono::seconds(0xffffffffL));
v +=
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(0x3b9ac9ffL) // 999,999,999
);
msgpack::zone z;
msgpack::object obj(v, z);
EXPECT_TRUE(obj.as<std::chrono::system_clock::time_point>() == v);
}
TEST(object_with_zone, system_clock_impl_min)
{
std::chrono::system_clock::time_point v(std::chrono::system_clock::time_point::min());
msgpack::zone z;
msgpack::object obj(v, z);
EXPECT_TRUE(obj.as<std::chrono::system_clock::time_point>() == v);
}
TEST(object_with_zone, system_clock_impl_max)
{
std::chrono::system_clock::time_point v(std::chrono::system_clock::time_point::max());
msgpack::zone z;
msgpack::object obj(v, z);
EXPECT_TRUE(obj.as<std::chrono::system_clock::time_point>() == v);
}
#endif // !defined(MSGPACK_USE_CPP03)
TEST(object_with_zone, ext_empty)