Skip to content

Commit 1fb1dad

Browse files
authored
Merge pull request #1076 from uyha/chrono-no-boost
remove dependency on boost in chrono.hpp
2 parents 2d65f66 + 4bc88d7 commit 1fb1dad

File tree

4 files changed

+125
-24
lines changed

4 files changed

+125
-24
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,8 @@ Makefile
4949
/test/streaming_c
5050
/test/version
5151
/test/zone
52+
53+
build
54+
*-build
55+
.cache
56+
compile_commands.json

include/msgpack/type.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@
3737
#include "adaptor/cpp11/array_char.hpp"
3838
#include "adaptor/cpp11/array_unsigned_char.hpp"
3939

40-
#if !defined(MSGPACK_NO_BOOST)
4140
#include "adaptor/cpp11/chrono.hpp"
42-
#endif // !defined(MSGPACK_NO_BOOST)
4341

4442
#include "adaptor/cpp11/forward_list.hpp"
4543
#include "adaptor/cpp11/reference_wrapper.hpp"

include/msgpack/v1/adaptor/cpp11/chrono.hpp

Lines changed: 120 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,14 @@
1111
#ifndef MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
1212
#define MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
1313

14-
#if !defined(MSGPACK_NO_BOOST)
15-
1614
#include "msgpack/versioning.hpp"
1715
#include "msgpack/adaptor/adaptor_base.hpp"
1816
#include "msgpack/object.hpp"
1917
#include "msgpack/adaptor/check_container_size.hpp"
2018

19+
#include <limits>
2120
#include <chrono>
2221

23-
#include <boost/numeric/conversion/cast.hpp>
24-
2522
namespace msgpack {
2623

2724
/// @cond
@@ -30,6 +27,113 @@ MSGPACK_API_VERSION_NAMESPACE(v1) {
3027

3128
namespace adaptor {
3229

30+
namespace detail {
31+
template <
32+
typename Target,
33+
typename Source,
34+
bool target_is_signed = std::is_signed<Target>::value,
35+
bool source_is_signed = std::is_signed<Source>::value,
36+
typename = typename std::enable_if<
37+
std::is_integral<Target>::value &&
38+
std::is_integral<Source>::value
39+
>::type
40+
>
41+
struct would_underflow {
42+
// The default case includes the cases that Source being unsigned, and since Source
43+
// is unsigned, no underflow can happen
44+
would_underflow(Source) : value{false} {}
45+
bool value;
46+
};
47+
48+
template <typename Target, typename Source>
49+
struct would_underflow<Target, Source, false, true> {
50+
// When Source is signed and Target is unsigned, we only need to compare with 0 to
51+
// detect underflow, this works correctly and also avoids warnings from the compiler
52+
would_underflow(Source source) : value{source < 0} {}
53+
bool value;
54+
};
55+
template <typename Target, typename Source>
56+
struct would_underflow<Target, Source, true, true> {
57+
// When Source and Target are signed, the promotion rules apply sensibly so we do
58+
// not need to do anything
59+
would_underflow(Source source)
60+
: value{source < std::numeric_limits<Target>::min()} {}
61+
bool value;
62+
};
63+
64+
template <
65+
typename Target,
66+
typename Source,
67+
bool target_is_signed = std::is_signed<Target>::value,
68+
bool source_is_signed = std::is_signed<Source>::value,
69+
typename = typename std::enable_if<
70+
std::is_integral<Target>::value &&
71+
std::is_integral<Source>::value
72+
>::type
73+
>
74+
struct would_overflow {
75+
// The default case is Source and Target having the same signedness, the promotion
76+
// rule also apply sensibly here so nothing special needs to be done
77+
would_overflow(Source source)
78+
: value{source > std::numeric_limits<Target>::max()} {}
79+
bool value;
80+
};
81+
template <typename Target, typename Source>
82+
struct would_overflow <Target, Source, false, true> {
83+
// When Target is unsigned and Source is signed, we cannot rely on the promotion
84+
// rule.
85+
would_overflow(Source source)
86+
: value{
87+
sizeof(Target) >= sizeof(Source)
88+
// Given Source is signed, Target being unsigned and having at least the
89+
// same size makes impossible to overflow
90+
? false
91+
// Source being larger than Target makes it safe to cast the maximum value
92+
// of Target to Source
93+
: source > static_cast<Source>(std::numeric_limits<Target>::max())
94+
} {}
95+
bool value;
96+
};
97+
template <typename Target, typename Source>
98+
struct would_overflow <Target, Source, true, false> {
99+
// When Target is signed and Source is unsigned, we cannot rely on the promotion
100+
// rule.
101+
would_overflow(Source source)
102+
: value{
103+
sizeof(Target) > sizeof(Source)
104+
// Target being larger than Source makes it impossible to overflow
105+
? false
106+
// Source being unsigned and having at least the size of Target makes it
107+
// safe to cast the maximum value of Target to Source
108+
: source > static_cast<Source>(std::numeric_limits<Target>::max())
109+
} {}
110+
bool value;
111+
};
112+
113+
template <
114+
typename Target,
115+
typename Source,
116+
typename = typename std::enable_if<
117+
std::is_integral<Target>::value &&
118+
std::is_integral<Source>::value
119+
>::type
120+
>
121+
Target integral_cast(Source source) {
122+
if (would_underflow<Target, Source>(source).value) {
123+
throw std::underflow_error{
124+
"casting from Source to Target causes an underflow error"
125+
};
126+
}
127+
if(would_overflow<Target, Source>(source).value) {
128+
throw std::overflow_error{
129+
"casting from Source to Target causes an overflow error"
130+
};
131+
}
132+
133+
return static_cast<Target>(source);
134+
}
135+
} // namespace detail
136+
33137
template <typename Clock, typename Duration>
34138
struct as<std::chrono::time_point<Clock, Duration>> {
35139
typename std::chrono::time_point<Clock, Duration> operator()(msgpack::object const& o) const {
@@ -45,7 +149,7 @@ struct as<std::chrono::time_point<Clock, Duration>> {
45149
case 8: {
46150
uint64_t value;
47151
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
48-
uint32_t nanosec = boost::numeric_cast<uint32_t>(value >> 34);
152+
uint32_t nanosec = detail::integral_cast<uint32_t>(value >> 34);
49153
uint64_t sec = value & 0x00000003ffffffffLL;
50154
tp += std::chrono::duration_cast<Duration>(
51155
std::chrono::nanoseconds(nanosec));
@@ -69,7 +173,7 @@ struct as<std::chrono::time_point<Clock, Duration>> {
69173
else {
70174
++sec;
71175
tp += std::chrono::seconds(sec);
72-
int64_t ns = boost::numeric_cast<int64_t>(nanosec) - 1000000000L;
176+
int64_t ns = detail::integral_cast<int64_t>(nanosec) - 1000000000L;
73177
tp += std::chrono::duration_cast<Duration>(
74178
std::chrono::nanoseconds(ns));
75179
}
@@ -98,7 +202,7 @@ struct convert<std::chrono::time_point<Clock, Duration>> {
98202
case 8: {
99203
uint64_t value;
100204
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
101-
uint32_t nanosec = boost::numeric_cast<uint32_t>(value >> 34);
205+
uint32_t nanosec = detail::integral_cast<uint32_t>(value >> 34);
102206
uint64_t sec = value & 0x00000003ffffffffLL;
103207
tp += std::chrono::duration_cast<Duration>(
104208
std::chrono::nanoseconds(nanosec));
@@ -123,7 +227,7 @@ struct convert<std::chrono::time_point<Clock, Duration>> {
123227
else {
124228
++sec;
125229
tp += std::chrono::seconds(sec);
126-
int64_t ns = boost::numeric_cast<int64_t>(nanosec) - 1000000000L;
230+
int64_t ns = detail::integral_cast<int64_t>(nanosec) - 1000000000L;
127231
tp += std::chrono::duration_cast<Duration>(
128232
std::chrono::nanoseconds(ns));
129233
}
@@ -142,7 +246,7 @@ template <typename Clock, typename Duration>
142246
struct pack<std::chrono::time_point<Clock, Duration>> {
143247
template <typename Stream>
144248
msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, std::chrono::time_point<Clock, Duration> const& v) const {
145-
int64_t count = boost::numeric_cast<int64_t>(v.time_since_epoch().count());
249+
int64_t count = detail::integral_cast<int64_t>(v.time_since_epoch().count());
146250
int64_t nano_num =
147251
Duration::period::ratio::num *
148252
(1000000000L / Duration::period::ratio::den);
@@ -158,11 +262,11 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
158262
/ Duration::period::ratio::den;
159263

160264
if ((sec >> 34) == 0) {
161-
uint64_t data64 = (boost::numeric_cast<uint64_t>(nanosec) << 34) | boost::numeric_cast<uint64_t>(sec);
265+
uint64_t data64 = (detail::integral_cast<uint64_t>(nanosec) << 34) | detail::integral_cast<uint64_t>(sec);
162266
if ((data64 & 0xffffffff00000000L) == 0) {
163267
// timestamp 32
164268
o.pack_ext(4, -1);
165-
uint32_t data32 = boost::numeric_cast<uint32_t>(data64);
269+
uint32_t data32 = detail::integral_cast<uint32_t>(data64);
166270
char buf[4];
167271
_msgpack_store32(buf, data32);
168272
o.pack_ext_body(buf, 4);
@@ -181,7 +285,7 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
181285
char buf[12];
182286

183287

184-
_msgpack_store32(&buf[0], boost::numeric_cast<uint32_t>(nanosec));
288+
_msgpack_store32(&buf[0], detail::integral_cast<uint32_t>(nanosec));
185289
_msgpack_store64(&buf[4], sec);
186290
o.pack_ext_body(buf, 12);
187291
}
@@ -192,7 +296,7 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
192296
template <typename Clock, typename Duration>
193297
struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
194298
void operator()(msgpack::object::with_zone& o, const std::chrono::time_point<Clock, Duration>& v) const {
195-
int64_t count = boost::numeric_cast<int64_t>(v.time_since_epoch().count());
299+
int64_t count = detail::integral_cast<int64_t>(v.time_since_epoch().count());
196300

197301
int64_t nano_num =
198302
Duration::period::ratio::num *
@@ -208,14 +312,14 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
208312
* Duration::period::ratio::num
209313
/ Duration::period::ratio::den;
210314
if ((sec >> 34) == 0) {
211-
uint64_t data64 = (boost::numeric_cast<uint64_t>(nanosec) << 34) | boost::numeric_cast<uint64_t>(sec);
315+
uint64_t data64 = (detail::integral_cast<uint64_t>(nanosec) << 34) | detail::integral_cast<uint64_t>(sec);
212316
if ((data64 & 0xffffffff00000000L) == 0) {
213317
// timestamp 32
214318
o.type = msgpack::type::EXT;
215319
o.via.ext.size = 4;
216320
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
217321
p[0] = static_cast<char>(-1);
218-
uint32_t data32 = boost::numeric_cast<uint32_t>(data64);
322+
uint32_t data32 = detail::integral_cast<uint32_t>(data64);
219323
_msgpack_store32(&p[1], data32);
220324
o.via.ext.ptr = p;
221325
}
@@ -235,7 +339,7 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
235339
o.via.ext.size = 12;
236340
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
237341
p[0] = static_cast<char>(-1);
238-
_msgpack_store32(&p[1], boost::numeric_cast<uint32_t>(nanosec));
342+
_msgpack_store32(&p[1], detail::integral_cast<uint32_t>(nanosec));
239343
_msgpack_store64(&p[1 + 4], sec);
240344
o.via.ext.ptr = p;
241345
}
@@ -250,6 +354,4 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
250354

251355
} // namespace msgpack
252356

253-
#endif // !defined(MSGPACK_NO_BOOST)
254-
255357
#endif // MSGPACK_V1_TYPE_CPP11_CHRONO_HPP

test/msgpack_cpp11.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -870,8 +870,6 @@ BOOST_AUTO_TEST_CASE(no_def_con_array_simple_buffer)
870870
BOOST_CHECK(val1 == val2);
871871
}
872872

873-
#if !defined(MSGPACK_NO_BOOST)
874-
875873
BOOST_AUTO_TEST_CASE(system_clock)
876874
{
877875
std::chrono::system_clock::time_point val1;
@@ -1437,8 +1435,6 @@ BOOST_AUTO_TEST_CASE(high_resolution_clock_impl_now)
14371435
BOOST_CHECK(val1 == val3);
14381436
}
14391437

1440-
#endif // !defined(MSGPACK_NO_BOOST)
1441-
14421438

14431439
BOOST_AUTO_TEST_CASE(timespec_pack_convert_zero)
14441440
{

0 commit comments

Comments
 (0)