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