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,97 @@ MSGPACK_API_VERSION_NAMESPACE(v1) {
3027
3128namespace 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+
33121template <typename Clock, typename Duration>
34122struct 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>
142230struct 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>> {
192280template <typename Clock, typename Duration>
193281struct 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
0 commit comments