Skip to content

Commit f2ffcf0

Browse files
committed
remove dependency on boost in chrono.hpp
1 parent ac062e2 commit f2ffcf0

File tree

3 files changed

+104
-24
lines changed

3 files changed

+104
-24
lines changed

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: 104 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,97 @@ MSGPACK_API_VERSION_NAMESPACE(v1) {
3027

3128
namespace adaptor {
3229

30+
namespace detail {
31+
template<typename Target,
32+
typename Source,
33+
bool target_is_signed = std::is_signed<Target>::value,
34+
bool source_is_signed = std::is_signed<Source>::value,
35+
typename = typename std::enable_if<
36+
std::is_integral<Target>::value &&
37+
std::is_integral<Source>::value
38+
>::type>
39+
struct would_underflow {
40+
// The default case includes the cases that Source being unsigned, and since Source
41+
// is unsigned, no underflow can happen
42+
would_underflow(Source) : value{false} {}
43+
bool value;
44+
};
45+
46+
template<typename Target, typename Source>
47+
struct would_underflow<Target, Source, false, true> {
48+
// When Source is signed and Target is unsigned, we only need to compare with 0 to
49+
// detect underflow, this works correctly and also avoids warnign from the compiler
50+
would_underflow(Source source) : value{source < 0} {}
51+
bool value;
52+
};
53+
template<typename Target, typename Source>
54+
struct would_underflow<Target, Source, true, true> {
55+
// When Source and Target are signed, the promotion rules apply sensibly so we do not
56+
// need to do anything
57+
would_underflow(Source source) : value{source < std::numeric_limits<Target>::min()} {}
58+
bool value;
59+
};
60+
61+
template<typename Target,
62+
typename Source,
63+
bool target_is_signed = std::is_signed<Target>::value,
64+
bool source_is_signed = std::is_signed<Source>::value,
65+
typename = typename std::enable_if<
66+
std::is_integral<Target>::value &&
67+
std::is_integral<Source>::value
68+
>::type>
69+
struct would_overflow {
70+
// The default case is Source and Target having the same signedness, the promotion
71+
// rules also apply sensibly here so nothing special needs to be done
72+
would_overflow(Source source) : value{source > std::numeric_limits<Target>::max()} {}
73+
bool value;
74+
};
75+
template<typename Target, typename Source>
76+
struct would_overflow <Target, Source, false, true> {
77+
// When Target is unsigned and Source is signed, we cannot rely on the promotion
78+
// rules.
79+
would_overflow(Source source)
80+
: value{ sizeof(Target) >= sizeof(Source)
81+
// Given Source is signed, Target being unsigned and having at least the
82+
// same size makes impossible to overflow
83+
? false
84+
// Source being larger than Target makes it safe to cast the maximum value
85+
// of Target to Source
86+
: source > static_cast<Source>(std::numeric_limits<Target>::max())} {}
87+
bool value;
88+
};
89+
template<typename Target, typename Source>
90+
struct would_overflow <Target, Source, true, false> {
91+
// When Target is signed and Source is unsigned, we cannot rely on the promotion
92+
// rules.
93+
would_overflow(Source source)
94+
: value{ sizeof(Target) > sizeof(Source)
95+
// Target being larger than Source makes it impossible to overflow
96+
? false
97+
// Source being unsigned and having at least the size of Target makes it
98+
// safe to cast the maximum value of Target to Source
99+
: source > static_cast<Source>(std::numeric_limits<Target>::max())} {}
100+
bool value;
101+
};
102+
103+
template<typename Target,
104+
typename Source,
105+
typename = typename std::enable_if<
106+
std::is_integral<Target>::value &&
107+
std::is_integral<Source>::value
108+
>::type>
109+
Target integral_cast(Source source) {
110+
if (would_underflow<Target, Source>(source).value) {
111+
throw std::underflow_error{"casting from Source to Target causes an underflow error"};
112+
}
113+
if(would_overflow<Target, Source>(source).value) {
114+
throw std::overflow_error{"casting from Source to Target causes an overflow error"};;
115+
}
116+
117+
return static_cast<Target>(source);
118+
}
119+
}
120+
33121
template <typename Clock, typename Duration>
34122
struct as<std::chrono::time_point<Clock, Duration>> {
35123
typename std::chrono::time_point<Clock, Duration> operator()(msgpack::object const& o) const {
@@ -45,7 +133,7 @@ struct as<std::chrono::time_point<Clock, Duration>> {
45133
case 8: {
46134
uint64_t value;
47135
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
48-
uint32_t nanosec = boost::numeric_cast<uint32_t>(value >> 34);
136+
uint32_t nanosec = detail::integral_cast<uint32_t>(value >> 34);
49137
uint64_t sec = value & 0x00000003ffffffffLL;
50138
tp += std::chrono::duration_cast<Duration>(
51139
std::chrono::nanoseconds(nanosec));
@@ -69,7 +157,7 @@ struct as<std::chrono::time_point<Clock, Duration>> {
69157
else {
70158
++sec;
71159
tp += std::chrono::seconds(sec);
72-
int64_t ns = boost::numeric_cast<int64_t>(nanosec) - 1000000000L;
160+
int64_t ns = detail::integral_cast<int64_t>(nanosec) - 1000000000L;
73161
tp += std::chrono::duration_cast<Duration>(
74162
std::chrono::nanoseconds(ns));
75163
}
@@ -98,7 +186,7 @@ struct convert<std::chrono::time_point<Clock, Duration>> {
98186
case 8: {
99187
uint64_t value;
100188
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
101-
uint32_t nanosec = boost::numeric_cast<uint32_t>(value >> 34);
189+
uint32_t nanosec = detail::integral_cast<uint32_t>(value >> 34);
102190
uint64_t sec = value & 0x00000003ffffffffLL;
103191
tp += std::chrono::duration_cast<Duration>(
104192
std::chrono::nanoseconds(nanosec));
@@ -123,7 +211,7 @@ struct convert<std::chrono::time_point<Clock, Duration>> {
123211
else {
124212
++sec;
125213
tp += std::chrono::seconds(sec);
126-
int64_t ns = boost::numeric_cast<int64_t>(nanosec) - 1000000000L;
214+
int64_t ns = detail::integral_cast<int64_t>(nanosec) - 1000000000L;
127215
tp += std::chrono::duration_cast<Duration>(
128216
std::chrono::nanoseconds(ns));
129217
}
@@ -142,7 +230,7 @@ template <typename Clock, typename Duration>
142230
struct pack<std::chrono::time_point<Clock, Duration>> {
143231
template <typename Stream>
144232
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());
233+
int64_t count = detail::integral_cast<int64_t>(v.time_since_epoch().count());
146234
int64_t nano_num =
147235
Duration::period::ratio::num *
148236
(1000000000L / Duration::period::ratio::den);
@@ -158,11 +246,11 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
158246
/ Duration::period::ratio::den;
159247

160248
if ((sec >> 34) == 0) {
161-
uint64_t data64 = (boost::numeric_cast<uint64_t>(nanosec) << 34) | boost::numeric_cast<uint64_t>(sec);
249+
uint64_t data64 = (detail::integral_cast<uint64_t>(nanosec) << 34) | detail::integral_cast<uint64_t>(sec);
162250
if ((data64 & 0xffffffff00000000L) == 0) {
163251
// timestamp 32
164252
o.pack_ext(4, -1);
165-
uint32_t data32 = boost::numeric_cast<uint32_t>(data64);
253+
uint32_t data32 = detail::integral_cast<uint32_t>(data64);
166254
char buf[4];
167255
_msgpack_store32(buf, data32);
168256
o.pack_ext_body(buf, 4);
@@ -181,7 +269,7 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
181269
char buf[12];
182270

183271

184-
_msgpack_store32(&buf[0], boost::numeric_cast<uint32_t>(nanosec));
272+
_msgpack_store32(&buf[0], detail::integral_cast<uint32_t>(nanosec));
185273
_msgpack_store64(&buf[4], sec);
186274
o.pack_ext_body(buf, 12);
187275
}
@@ -192,7 +280,7 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
192280
template <typename Clock, typename Duration>
193281
struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
194282
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());
283+
int64_t count = detail::integral_cast<int64_t>(v.time_since_epoch().count());
196284

197285
int64_t nano_num =
198286
Duration::period::ratio::num *
@@ -208,14 +296,14 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
208296
* Duration::period::ratio::num
209297
/ Duration::period::ratio::den;
210298
if ((sec >> 34) == 0) {
211-
uint64_t data64 = (boost::numeric_cast<uint64_t>(nanosec) << 34) | boost::numeric_cast<uint64_t>(sec);
299+
uint64_t data64 = (detail::integral_cast<uint64_t>(nanosec) << 34) | detail::integral_cast<uint64_t>(sec);
212300
if ((data64 & 0xffffffff00000000L) == 0) {
213301
// timestamp 32
214302
o.type = msgpack::type::EXT;
215303
o.via.ext.size = 4;
216304
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
217305
p[0] = static_cast<char>(-1);
218-
uint32_t data32 = boost::numeric_cast<uint32_t>(data64);
306+
uint32_t data32 = detail::integral_cast<uint32_t>(data64);
219307
_msgpack_store32(&p[1], data32);
220308
o.via.ext.ptr = p;
221309
}
@@ -235,7 +323,7 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
235323
o.via.ext.size = 12;
236324
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
237325
p[0] = static_cast<char>(-1);
238-
_msgpack_store32(&p[1], boost::numeric_cast<uint32_t>(nanosec));
326+
_msgpack_store32(&p[1], detail::integral_cast<uint32_t>(nanosec));
239327
_msgpack_store64(&p[1 + 4], sec);
240328
o.via.ext.ptr = p;
241329
}
@@ -250,6 +338,4 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
250338

251339
} // namespace msgpack
252340

253-
#endif // !defined(MSGPACK_NO_BOOST)
254-
255341
#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)