Skip to content

Commit d5242a7

Browse files
authored
Merge pull request #781 from redboltz/add_timespec_for_cpp
Added timespec support for C++11 or later.
2 parents ce088e7 + d3fecce commit d5242a7

File tree

5 files changed

+313
-0
lines changed

5 files changed

+313
-0
lines changed

Files.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ IF (MSGPACK_ENABLE_CXX)
190190
include/msgpack/adaptor/cpp11/forward_list.hpp
191191
include/msgpack/adaptor/cpp11/reference_wrapper.hpp
192192
include/msgpack/adaptor/cpp11/shared_ptr.hpp
193+
include/msgpack/adaptor/cpp11/timespec.hpp
193194
include/msgpack/adaptor/cpp11/tuple.hpp
194195
include/msgpack/adaptor/cpp11/unique_ptr.hpp
195196
include/msgpack/adaptor/cpp11/unordered_map.hpp
@@ -552,6 +553,7 @@ IF (MSGPACK_ENABLE_CXX)
552553
include/msgpack/v1/adaptor/cpp11/forward_list.hpp
553554
include/msgpack/v1/adaptor/cpp11/reference_wrapper.hpp
554555
include/msgpack/v1/adaptor/cpp11/shared_ptr.hpp
556+
include/msgpack/v1/adaptor/cpp11/timespec.hpp
555557
include/msgpack/v1/adaptor/cpp11/tuple.hpp
556558
include/msgpack/v1/adaptor/cpp11/unique_ptr.hpp
557559
include/msgpack/v1/adaptor/cpp11/unordered_map.hpp
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// MessagePack for C++ static resolution routine
3+
//
4+
// Copyright (C) 2019 KONDO Takatoshi
5+
//
6+
// Distributed under the Boost Software License, Version 1.0.
7+
// (See accompanying file LICENSE_1_0.txt or copy at
8+
// http://www.boost.org/LICENSE_1_0.txt)
9+
//
10+
11+
#ifndef MSGPACK_TYPE_CPP11_TIMESPEC_HPP
12+
#define MSGPACK_TYPE_CPP11_TIMESPEC_HPP
13+
14+
#include "msgpack/v1/adaptor/cpp11/timespec.hpp"
15+
16+
#endif // MSGPACK_TYPE_CPP11_TIMESPEC_HPP

include/msgpack/type.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "adaptor/cpp11/forward_list.hpp"
4040
#include "adaptor/cpp11/reference_wrapper.hpp"
4141
#include "adaptor/cpp11/shared_ptr.hpp"
42+
#include "adaptor/cpp11/timespec.hpp"
4243
#include "adaptor/cpp11/tuple.hpp"
4344
#include "adaptor/cpp11/unique_ptr.hpp"
4445
#include "adaptor/cpp11/unordered_map.hpp"
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//
2+
// MessagePack for C++ static resolution routine
3+
//
4+
// Copyright (C) 2018 KONDO Takatoshi
5+
//
6+
// Distributed under the Boost Software License, Version 1.0.
7+
// (See accompanying file LICENSE_1_0.txt or copy at
8+
// http://www.boost.org/LICENSE_1_0.txt)
9+
//
10+
#ifndef MSGPACK_V1_TYPE_CPP11_TIMESPEC_HPP
11+
#define MSGPACK_V1_TYPE_CPP11_TIMESPEC_HPP
12+
13+
#include "msgpack/versioning.hpp"
14+
#include "msgpack/adaptor/adaptor_base.hpp"
15+
#include "msgpack/object.hpp"
16+
17+
#include <ctime>
18+
19+
namespace msgpack {
20+
21+
/// @cond
22+
MSGPACK_API_VERSION_NAMESPACE(v1) {
23+
/// @endcond
24+
25+
namespace adaptor {
26+
27+
template <>
28+
struct convert<timespec> {
29+
msgpack::object const& operator()(msgpack::object const& o, timespec& v) const {
30+
if(o.type != msgpack::type::EXT) { throw msgpack::type_error(); }
31+
if(o.via.ext.type() != -1) { throw msgpack::type_error(); }
32+
switch(o.via.ext.size) {
33+
case 4: {
34+
uint32_t sec;
35+
_msgpack_load32(uint32_t, o.via.ext.data(), &sec);
36+
v.tv_sec = static_cast<decltype(v.tv_sec)>(sec);
37+
v.tv_nsec = 0;
38+
} break;
39+
case 8: {
40+
uint64_t value;
41+
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
42+
v.tv_sec = static_cast<decltype(v.tv_sec)>(value & 0x00000003ffffffffLL);
43+
v.tv_nsec= static_cast<decltype(v.tv_nsec)>(value >> 34);
44+
} break;
45+
case 12: {
46+
uint32_t nanosec;
47+
_msgpack_load32(uint32_t, o.via.ext.data(), &nanosec);
48+
int64_t sec;
49+
_msgpack_load64(int64_t, o.via.ext.data() + 4, &sec);
50+
v.tv_sec = static_cast<decltype(v.tv_sec)>(sec);
51+
v.tv_nsec = static_cast<decltype(v.tv_nsec)>(nanosec);
52+
} break;
53+
default:
54+
throw msgpack::type_error();
55+
}
56+
return o;
57+
}
58+
};
59+
60+
template <>
61+
struct pack<timespec> {
62+
template <typename Stream>
63+
msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const timespec& v) const {
64+
if ((static_cast<uint64_t>(v.tv_sec) >> 34) == 0) {
65+
uint64_t data64 = (static_cast<uint64_t>(v.tv_nsec) << 34) | static_cast<uint64_t>(v.tv_sec);
66+
if ((data64 & 0xffffffff00000000L) == 0) {
67+
// timestamp 32
68+
o.pack_ext(4, -1);
69+
uint32_t data32 = static_cast<uint32_t>(data64);
70+
char buf[4];
71+
_msgpack_store32(buf, data32);
72+
o.pack_ext_body(buf, 4);
73+
}
74+
else {
75+
// timestamp 64
76+
o.pack_ext(8, -1);
77+
char buf[8];
78+
_msgpack_store64(buf, data64);
79+
o.pack_ext_body(buf, 8);
80+
}
81+
}
82+
else {
83+
// timestamp 96
84+
o.pack_ext(12, -1);
85+
char buf[12];
86+
_msgpack_store32(&buf[0], static_cast<uint32_t>(v.tv_nsec));
87+
_msgpack_store64(&buf[4], v.tv_sec);
88+
o.pack_ext_body(buf, 12);
89+
}
90+
return o;
91+
}
92+
};
93+
94+
template <>
95+
struct object_with_zone<timespec> {
96+
void operator()(msgpack::object::with_zone& o, const timespec& v) const {
97+
if ((static_cast<uint64_t>(v.tv_sec) >> 34) == 0) {
98+
uint64_t data64 = (static_cast<uint64_t>(v.tv_nsec) << 34) | static_cast<uint64_t>(v.tv_sec);
99+
if ((data64 & 0xffffffff00000000L) == 0) {
100+
// timestamp 32
101+
o.type = msgpack::type::EXT;
102+
o.via.ext.size = 4;
103+
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
104+
p[0] = static_cast<char>(-1);
105+
uint32_t data32 = static_cast<uint32_t>(data64);
106+
_msgpack_store32(&p[1], data32);
107+
o.via.ext.ptr = p;
108+
}
109+
else {
110+
// timestamp 64
111+
o.type = msgpack::type::EXT;
112+
o.via.ext.size = 8;
113+
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
114+
p[0] = static_cast<char>(-1);
115+
_msgpack_store64(&p[1], data64);
116+
o.via.ext.ptr = p;
117+
}
118+
}
119+
else {
120+
// timestamp 96
121+
o.type = msgpack::type::EXT;
122+
o.via.ext.size = 12;
123+
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
124+
p[0] = static_cast<char>(-1);
125+
_msgpack_store32(&p[1], static_cast<uint32_t>(v.tv_nsec));
126+
_msgpack_store64(&p[1 + 4], v.tv_sec);
127+
o.via.ext.ptr = p;
128+
}
129+
}
130+
};
131+
132+
} // namespace adaptor
133+
134+
/// @cond
135+
} // MSGPACK_API_VERSION_NAMESPACE(v1)
136+
/// @endcond
137+
138+
} // namespace msgpack
139+
140+
#endif // MSGPACK_V1_TYPE_CPP11_TIMESPEC_HPP

test/msgpack_cpp11.cpp

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,4 +1049,158 @@ TEST(MSGPACK_CHRONO, system_clock_impl_now)
10491049
EXPECT_EQ(val1, val3);
10501050
}
10511051

1052+
TEST(MSGPACK_TIMESPEC, timespec_pack_convert_zero)
1053+
{
1054+
std::stringstream ss;
1055+
timespec val1{ 0, 0 };
1056+
1057+
msgpack::pack(ss, val1);
1058+
EXPECT_EQ(ss.str().data()[0], static_cast<char>(0xd6));
1059+
1060+
msgpack::object_handle oh;
1061+
msgpack::unpack(oh, ss.str().data(), ss.str().size());
1062+
timespec val2 = oh.get().as<timespec>();
1063+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1064+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1065+
}
1066+
1067+
TEST(MSGPACK_TIMESPEC, timespec_object_with_zone_zero)
1068+
{
1069+
msgpack::zone z;
1070+
timespec val1{ 0, 0 };
1071+
msgpack::object obj(val1, z);
1072+
timespec val2 = obj.as<timespec>();
1073+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1074+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1075+
}
1076+
1077+
TEST(MSGPACK_TIMESPEC, timespec_pack_convert_32bit_sec)
1078+
{
1079+
std::stringstream ss;
1080+
timespec val1{ 0xffffffffUL, 0 };
1081+
1082+
msgpack::pack(ss, val1);
1083+
EXPECT_EQ(ss.str().data()[0], static_cast<char>(0xd6));
1084+
1085+
msgpack::object_handle oh;
1086+
msgpack::unpack(oh, ss.str().data(), ss.str().size());
1087+
timespec val2 = oh.get().as<timespec>();
1088+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1089+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1090+
}
1091+
1092+
TEST(MSGPACK_TIMESPEC, timespec_object_with_zone_32bit_sec)
1093+
{
1094+
msgpack::zone z;
1095+
timespec val1{ 0xffffffffUL, 0 };
1096+
msgpack::object obj(val1, z);
1097+
timespec val2 = obj.as<timespec>();
1098+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1099+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1100+
}
1101+
1102+
TEST(MSGPACK_TIMESPEC, timespec_pack_convert_max_nano)
1103+
{
1104+
std::stringstream ss;
1105+
timespec val1{ 0, 999999999 };
1106+
1107+
msgpack::pack(ss, val1);
1108+
EXPECT_EQ(ss.str().data()[0], static_cast<char>(0xd7));
1109+
msgpack::object_handle oh;
1110+
msgpack::unpack(oh, ss.str().data(), ss.str().size());
1111+
timespec val2 = oh.get().as<timespec>();
1112+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1113+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1114+
}
1115+
1116+
TEST(MSGPACK_TIMESPEC, timespec_object_with_zone_max_nano)
1117+
{
1118+
msgpack::zone z;
1119+
timespec val1{ 0, 999999999 };
1120+
msgpack::object obj(val1, z);
1121+
timespec val2 = obj.as<timespec>();
1122+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1123+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1124+
}
1125+
1126+
TEST(MSGPACK_TIMESPEC, timespec_pack_convert_34bit_sec_max_nano)
1127+
{
1128+
if (sizeof(decltype(std::declval<timespec>().tv_sec)) <= 4) return;
1129+
std::stringstream ss;
1130+
timespec val1{ static_cast<decltype(std::declval<timespec>().tv_sec)>(0x3ffffffffULL), 999999999 };
1131+
1132+
msgpack::pack(ss, val1);
1133+
EXPECT_EQ(ss.str().data()[0], static_cast<char>(0xd7));
1134+
1135+
msgpack::object_handle oh;
1136+
msgpack::unpack(oh, ss.str().data(), ss.str().size());
1137+
timespec val2 = oh.get().as<timespec>();
1138+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1139+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1140+
}
1141+
1142+
TEST(MSGPACK_TIMESPEC, timespec_object_with_zone_34bit_sec_max_nano)
1143+
{
1144+
if (sizeof(decltype(std::declval<timespec>().tv_sec)) <= 4) return;
1145+
msgpack::zone z;
1146+
timespec val1{ static_cast<decltype(std::declval<timespec>().tv_sec)>(0x3ffffffffULL), 999999999 };
1147+
msgpack::object obj(val1, z);
1148+
timespec val2 = obj.as<timespec>();
1149+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1150+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1151+
}
1152+
1153+
TEST(MSGPACK_TIMESPEC, timespec_pack_convert_35bit_sec_max_nano)
1154+
{
1155+
if (sizeof(decltype(std::declval<timespec>().tv_sec)) <= 4) return;
1156+
std::stringstream ss;
1157+
timespec val1{ static_cast<decltype(std::declval<timespec>().tv_sec)>(0x7ffffffffULL), 999999999 };
1158+
1159+
msgpack::pack(ss, val1);
1160+
EXPECT_EQ(ss.str().data()[0], static_cast<char>(0xc7));
1161+
1162+
msgpack::object_handle oh;
1163+
msgpack::unpack(oh, ss.str().data(), ss.str().size());
1164+
timespec val2 = oh.get().as<timespec>();
1165+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1166+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1167+
}
1168+
1169+
TEST(MSGPACK_TIMESPEC, timespec_object_with_zone_35bit_sec_max_nano)
1170+
{
1171+
if (sizeof(decltype(std::declval<timespec>().tv_sec)) <= 4) return;
1172+
msgpack::zone z;
1173+
timespec val1{ static_cast<decltype(std::declval<timespec>().tv_sec)>(0x7ffffffffULL), 999999999 };
1174+
msgpack::object obj(val1, z);
1175+
timespec val2 = obj.as<timespec>();
1176+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1177+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1178+
}
1179+
1180+
TEST(MSGPACK_TIMESPEC, timespec_pack_convert_64bit_sec_max_nano)
1181+
{
1182+
std::stringstream ss;
1183+
timespec val1{ std::numeric_limits<decltype(std::declval<timespec>().tv_sec)>::max(), 999999999 };
1184+
1185+
msgpack::pack(ss, val1);
1186+
EXPECT_EQ(ss.str().data()[0], static_cast<char>(0xc7));
1187+
1188+
msgpack::object_handle oh;
1189+
msgpack::unpack(oh, ss.str().data(), ss.str().size());
1190+
timespec val2 = oh.get().as<timespec>();
1191+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1192+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1193+
}
1194+
1195+
TEST(MSGPACK_TIMESPEC, timespec_object_with_zone_64bit_sec_max_nano)
1196+
{
1197+
msgpack::zone z;
1198+
timespec val1{ std::numeric_limits<decltype(std::declval<timespec>().tv_sec)>::max(), 999999999 };
1199+
msgpack::object obj(val1, z);
1200+
timespec val2 = obj.as<timespec>();
1201+
EXPECT_EQ(val1.tv_sec, val2.tv_sec);
1202+
EXPECT_EQ(val1.tv_nsec, val2.tv_nsec);
1203+
}
1204+
1205+
10521206
#endif // !defined(MSGPACK_USE_CPP03)

0 commit comments

Comments
 (0)