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-
2522namespace msgpack {
2623
2724// / @cond
@@ -30,6 +27,113 @@ MSGPACK_API_VERSION_NAMESPACE(v1) {
3027
3128namespace 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+
33137template <typename Clock, typename Duration>
34138struct 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>
142246struct 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>> {
192296template <typename Clock, typename Duration>
193297struct 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
0 commit comments