Merge pull request #1076 from uyha/chrono-no-boost

remove dependency on boost in chrono.hpp
This commit is contained in:
Takatoshi Kondo 2023-07-06 09:11:42 +09:00 committed by GitHub
commit 1fb1dad6bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 24 deletions

5
.gitignore vendored
View File

@ -49,3 +49,8 @@ Makefile
/test/streaming_c
/test/version
/test/zone
build
*-build
.cache
compile_commands.json

View File

@ -37,9 +37,7 @@
#include "adaptor/cpp11/array_char.hpp"
#include "adaptor/cpp11/array_unsigned_char.hpp"
#if !defined(MSGPACK_NO_BOOST)
#include "adaptor/cpp11/chrono.hpp"
#endif // !defined(MSGPACK_NO_BOOST)
#include "adaptor/cpp11/forward_list.hpp"
#include "adaptor/cpp11/reference_wrapper.hpp"

View File

@ -11,17 +11,14 @@
#ifndef MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
#define MSGPACK_V1_TYPE_CPP11_CHRONO_HPP
#if !defined(MSGPACK_NO_BOOST)
#include "msgpack/versioning.hpp"
#include "msgpack/adaptor/adaptor_base.hpp"
#include "msgpack/object.hpp"
#include "msgpack/adaptor/check_container_size.hpp"
#include <limits>
#include <chrono>
#include <boost/numeric/conversion/cast.hpp>
namespace msgpack {
/// @cond
@ -30,6 +27,113 @@ MSGPACK_API_VERSION_NAMESPACE(v1) {
namespace adaptor {
namespace detail {
template <
typename Target,
typename Source,
bool target_is_signed = std::is_signed<Target>::value,
bool source_is_signed = std::is_signed<Source>::value,
typename = typename std::enable_if<
std::is_integral<Target>::value &&
std::is_integral<Source>::value
>::type
>
struct would_underflow {
// The default case includes the cases that Source being unsigned, and since Source
// is unsigned, no underflow can happen
would_underflow(Source) : value{false} {}
bool value;
};
template <typename Target, typename Source>
struct would_underflow<Target, Source, false, true> {
// When Source is signed and Target is unsigned, we only need to compare with 0 to
// detect underflow, this works correctly and also avoids warnings from the compiler
would_underflow(Source source) : value{source < 0} {}
bool value;
};
template <typename Target, typename Source>
struct would_underflow<Target, Source, true, true> {
// When Source and Target are signed, the promotion rules apply sensibly so we do
// not need to do anything
would_underflow(Source source)
: value{source < std::numeric_limits<Target>::min()} {}
bool value;
};
template <
typename Target,
typename Source,
bool target_is_signed = std::is_signed<Target>::value,
bool source_is_signed = std::is_signed<Source>::value,
typename = typename std::enable_if<
std::is_integral<Target>::value &&
std::is_integral<Source>::value
>::type
>
struct would_overflow {
// The default case is Source and Target having the same signedness, the promotion
// rule also apply sensibly here so nothing special needs to be done
would_overflow(Source source)
: value{source > std::numeric_limits<Target>::max()} {}
bool value;
};
template <typename Target, typename Source>
struct would_overflow <Target, Source, false, true> {
// When Target is unsigned and Source is signed, we cannot rely on the promotion
// rule.
would_overflow(Source source)
: value{
sizeof(Target) >= sizeof(Source)
// Given Source is signed, Target being unsigned and having at least the
// same size makes impossible to overflow
? false
// Source being larger than Target makes it safe to cast the maximum value
// of Target to Source
: source > static_cast<Source>(std::numeric_limits<Target>::max())
} {}
bool value;
};
template <typename Target, typename Source>
struct would_overflow <Target, Source, true, false> {
// When Target is signed and Source is unsigned, we cannot rely on the promotion
// rule.
would_overflow(Source source)
: value{
sizeof(Target) > sizeof(Source)
// Target being larger than Source makes it impossible to overflow
? false
// Source being unsigned and having at least the size of Target makes it
// safe to cast the maximum value of Target to Source
: source > static_cast<Source>(std::numeric_limits<Target>::max())
} {}
bool value;
};
template <
typename Target,
typename Source,
typename = typename std::enable_if<
std::is_integral<Target>::value &&
std::is_integral<Source>::value
>::type
>
Target integral_cast(Source source) {
if (would_underflow<Target, Source>(source).value) {
throw std::underflow_error{
"casting from Source to Target causes an underflow error"
};
}
if(would_overflow<Target, Source>(source).value) {
throw std::overflow_error{
"casting from Source to Target causes an overflow error"
};
}
return static_cast<Target>(source);
}
} // namespace detail
template <typename Clock, typename Duration>
struct as<std::chrono::time_point<Clock, Duration>> {
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>> {
case 8: {
uint64_t value;
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
uint32_t nanosec = boost::numeric_cast<uint32_t>(value >> 34);
uint32_t nanosec = detail::integral_cast<uint32_t>(value >> 34);
uint64_t sec = value & 0x00000003ffffffffLL;
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(nanosec));
@ -69,7 +173,7 @@ struct as<std::chrono::time_point<Clock, Duration>> {
else {
++sec;
tp += std::chrono::seconds(sec);
int64_t ns = boost::numeric_cast<int64_t>(nanosec) - 1000000000L;
int64_t ns = detail::integral_cast<int64_t>(nanosec) - 1000000000L;
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(ns));
}
@ -98,7 +202,7 @@ struct convert<std::chrono::time_point<Clock, Duration>> {
case 8: {
uint64_t value;
_msgpack_load64(uint64_t, o.via.ext.data(), &value);
uint32_t nanosec = boost::numeric_cast<uint32_t>(value >> 34);
uint32_t nanosec = detail::integral_cast<uint32_t>(value >> 34);
uint64_t sec = value & 0x00000003ffffffffLL;
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(nanosec));
@ -123,7 +227,7 @@ struct convert<std::chrono::time_point<Clock, Duration>> {
else {
++sec;
tp += std::chrono::seconds(sec);
int64_t ns = boost::numeric_cast<int64_t>(nanosec) - 1000000000L;
int64_t ns = detail::integral_cast<int64_t>(nanosec) - 1000000000L;
tp += std::chrono::duration_cast<Duration>(
std::chrono::nanoseconds(ns));
}
@ -142,7 +246,7 @@ template <typename Clock, typename Duration>
struct pack<std::chrono::time_point<Clock, Duration>> {
template <typename Stream>
msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, std::chrono::time_point<Clock, Duration> const& v) const {
int64_t count = boost::numeric_cast<int64_t>(v.time_since_epoch().count());
int64_t count = detail::integral_cast<int64_t>(v.time_since_epoch().count());
int64_t nano_num =
Duration::period::ratio::num *
(1000000000L / Duration::period::ratio::den);
@ -158,11 +262,11 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
/ Duration::period::ratio::den;
if ((sec >> 34) == 0) {
uint64_t data64 = (boost::numeric_cast<uint64_t>(nanosec) << 34) | boost::numeric_cast<uint64_t>(sec);
uint64_t data64 = (detail::integral_cast<uint64_t>(nanosec) << 34) | detail::integral_cast<uint64_t>(sec);
if ((data64 & 0xffffffff00000000L) == 0) {
// timestamp 32
o.pack_ext(4, -1);
uint32_t data32 = boost::numeric_cast<uint32_t>(data64);
uint32_t data32 = detail::integral_cast<uint32_t>(data64);
char buf[4];
_msgpack_store32(buf, data32);
o.pack_ext_body(buf, 4);
@ -181,7 +285,7 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
char buf[12];
_msgpack_store32(&buf[0], boost::numeric_cast<uint32_t>(nanosec));
_msgpack_store32(&buf[0], detail::integral_cast<uint32_t>(nanosec));
_msgpack_store64(&buf[4], sec);
o.pack_ext_body(buf, 12);
}
@ -192,7 +296,7 @@ struct pack<std::chrono::time_point<Clock, Duration>> {
template <typename Clock, typename Duration>
struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
void operator()(msgpack::object::with_zone& o, const std::chrono::time_point<Clock, Duration>& v) const {
int64_t count = boost::numeric_cast<int64_t>(v.time_since_epoch().count());
int64_t count = detail::integral_cast<int64_t>(v.time_since_epoch().count());
int64_t nano_num =
Duration::period::ratio::num *
@ -208,14 +312,14 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
* Duration::period::ratio::num
/ Duration::period::ratio::den;
if ((sec >> 34) == 0) {
uint64_t data64 = (boost::numeric_cast<uint64_t>(nanosec) << 34) | boost::numeric_cast<uint64_t>(sec);
uint64_t data64 = (detail::integral_cast<uint64_t>(nanosec) << 34) | detail::integral_cast<uint64_t>(sec);
if ((data64 & 0xffffffff00000000L) == 0) {
// timestamp 32
o.type = msgpack::type::EXT;
o.via.ext.size = 4;
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
p[0] = static_cast<char>(-1);
uint32_t data32 = boost::numeric_cast<uint32_t>(data64);
uint32_t data32 = detail::integral_cast<uint32_t>(data64);
_msgpack_store32(&p[1], data32);
o.via.ext.ptr = p;
}
@ -235,7 +339,7 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
o.via.ext.size = 12;
char* p = static_cast<char*>(o.zone.allocate_no_align(o.via.ext.size + 1));
p[0] = static_cast<char>(-1);
_msgpack_store32(&p[1], boost::numeric_cast<uint32_t>(nanosec));
_msgpack_store32(&p[1], detail::integral_cast<uint32_t>(nanosec));
_msgpack_store64(&p[1 + 4], sec);
o.via.ext.ptr = p;
}
@ -250,6 +354,4 @@ struct object_with_zone<std::chrono::time_point<Clock, Duration>> {
} // namespace msgpack
#endif // !defined(MSGPACK_NO_BOOST)
#endif // MSGPACK_V1_TYPE_CPP11_CHRONO_HPP

View File

@ -870,8 +870,6 @@ BOOST_AUTO_TEST_CASE(no_def_con_array_simple_buffer)
BOOST_CHECK(val1 == val2);
}
#if !defined(MSGPACK_NO_BOOST)
BOOST_AUTO_TEST_CASE(system_clock)
{
std::chrono::system_clock::time_point val1;
@ -1437,8 +1435,6 @@ BOOST_AUTO_TEST_CASE(high_resolution_clock_impl_now)
BOOST_CHECK(val1 == val3);
}
#endif // !defined(MSGPACK_NO_BOOST)
BOOST_AUTO_TEST_CASE(timespec_pack_convert_zero)
{