11
11
#ifndef MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
12
12
#define MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
13
13
14
- #if !defined(MSGPACK_NO_BOOST)
15
-
16
14
#include " msgpack/versioning.hpp"
17
15
#include " msgpack/adaptor/adaptor_base.hpp"
18
16
#include " msgpack/object.hpp"
19
17
#include " msgpack/adaptor/check_container_size.hpp"
20
18
19
+ #include < limits>
21
20
#include < chrono>
22
21
23
- #include < boost/numeric/conversion/cast.hpp>
24
-
25
22
namespace msgpack {
26
23
27
24
// / @cond
@@ -30,6 +27,97 @@ MSGPACK_API_VERSION_NAMESPACE(v1) {
30
27
31
28
namespace adaptor {
32
29
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
+
33
121
template <typename Clock, typename Duration>
34
122
struct as <std::chrono::time_point<Clock, Duration>> {
35
123
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>> {
45
133
case 8 : {
46
134
uint64_t value;
47
135
_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 );
49
137
uint64_t sec = value & 0x00000003ffffffffLL ;
50
138
tp += std::chrono::duration_cast<Duration>(
51
139
std::chrono::nanoseconds (nanosec));
@@ -69,7 +157,7 @@ struct as<std::chrono::time_point<Clock, Duration>> {
69
157
else {
70
158
++sec;
71
159
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 ;
73
161
tp += std::chrono::duration_cast<Duration>(
74
162
std::chrono::nanoseconds (ns));
75
163
}
@@ -98,7 +186,7 @@ struct convert<std::chrono::time_point<Clock, Duration>> {
98
186
case 8 : {
99
187
uint64_t value;
100
188
_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 );
102
190
uint64_t sec = value & 0x00000003ffffffffLL ;
103
191
tp += std::chrono::duration_cast<Duration>(
104
192
std::chrono::nanoseconds (nanosec));
@@ -123,7 +211,7 @@ struct convert<std::chrono::time_point<Clock, Duration>> {
123
211
else {
124
212
++sec;
125
213
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 ;
127
215
tp += std::chrono::duration_cast<Duration>(
128
216
std::chrono::nanoseconds (ns));
129
217
}
@@ -142,7 +230,7 @@ template <typename Clock, typename Duration>
142
230
struct pack <std::chrono::time_point<Clock, Duration>> {
143
231
template <typename Stream>
144
232
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 ());
146
234
int64_t nano_num =
147
235
Duration::period::ratio::num *
148
236
(1000000000L / Duration::period::ratio::den);
@@ -158,11 +246,11 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
158
246
/ Duration::period::ratio::den;
159
247
160
248
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);
162
250
if ((data64 & 0xffffffff00000000L ) == 0 ) {
163
251
// timestamp 32
164
252
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);
166
254
char buf[4 ];
167
255
_msgpack_store32 (buf, data32);
168
256
o.pack_ext_body (buf, 4 );
@@ -181,7 +269,7 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
181
269
char buf[12 ];
182
270
183
271
184
- _msgpack_store32 (&buf[0 ], boost::numeric_cast <uint32_t >(nanosec));
272
+ _msgpack_store32 (&buf[0 ], detail::integral_cast <uint32_t >(nanosec));
185
273
_msgpack_store64 (&buf[4 ], sec);
186
274
o.pack_ext_body (buf, 12 );
187
275
}
@@ -192,7 +280,7 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
192
280
template <typename Clock, typename Duration>
193
281
struct object_with_zone <std::chrono::time_point<Clock, Duration>> {
194
282
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 ());
196
284
197
285
int64_t nano_num =
198
286
Duration::period::ratio::num *
@@ -208,14 +296,14 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
208
296
* Duration::period::ratio::num
209
297
/ Duration::period::ratio::den;
210
298
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);
212
300
if ((data64 & 0xffffffff00000000L ) == 0 ) {
213
301
// timestamp 32
214
302
o.type = msgpack::type::EXT;
215
303
o.via .ext .size = 4 ;
216
304
char * p = static_cast <char *>(o.zone .allocate_no_align (o.via .ext .size + 1 ));
217
305
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);
219
307
_msgpack_store32 (&p[1 ], data32);
220
308
o.via .ext .ptr = p;
221
309
}
@@ -235,7 +323,7 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
235
323
o.via .ext .size = 12 ;
236
324
char * p = static_cast <char *>(o.zone .allocate_no_align (o.via .ext .size + 1 ));
237
325
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));
239
327
_msgpack_store64 (&p[1 + 4 ], sec);
240
328
o.via .ext .ptr = p;
241
329
}
@@ -250,6 +338,4 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
250
338
251
339
} // namespace msgpack
252
340
253
- #endif // !defined(MSGPACK_NO_BOOST)
254
-
255
341
#endif // MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
0 commit comments