Skip to content

Commit

Permalink
Merge pull request #1071 from redboltz/fix_1070
Browse files Browse the repository at this point in the history
Fixed #1070.
  • Loading branch information
redboltz committed May 15, 2023
2 parents 706fde4 + 34f8fd6 commit ac062e2
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 38 deletions.
60 changes: 29 additions & 31 deletions include/msgpack/v1/adaptor/boost/msgpack_variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ struct basic_variant :
int_init(v);
}
basic_variant(unsigned long long v):base(uint64_t(v)) {}
basic_variant(float v) {
double_init(v);
}
basic_variant(double v) {
double_init(v);
}

bool is_nil() const {
return boost::get<msgpack::type::nil_t>(this) != MSGPACK_NULLPTR;
Expand Down Expand Up @@ -177,71 +183,50 @@ struct basic_variant :
int64_t as_int64_t() const {
return boost::get<int64_t>(*this);
}
int64_t& as_int64_t() {
return boost::get<int64_t>(*this);
}
uint64_t as_uint64_t() const {
return boost::get<uint64_t>(*this);
}
uint64_t& as_uint64_t() {
return boost::get<uint64_t>(*this);
}
double as_double() const {
return boost::get<double>(*this);
}
double& as_double() {
return boost::get<double>(*this);
if (is_double()) {
return boost::get<double>(*this);
}
if (is_int64_t()) {
return static_cast<double>(boost::get<int64_t>(*this));
}
if (is_uint64_t()) {
return static_cast<double>(boost::get<uint64_t>(*this));
}
throw msgpack::type_error();
}
std::string const& as_string() const {
return boost::get<std::string>(*this);
}
std::string& as_string() {
return boost::get<std::string>(*this);
}
#if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53
boost::string_ref const& as_boost_string_ref() const {
return boost::get<boost::string_ref>(*this);
}
boost::string_ref& as_boost_string_ref() {
return boost::get<boost::string_ref>(*this);
}
#endif // (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53
std::vector<char> const& as_vector_char() const {
return boost::get<std::vector<char> >(*this);
}
std::vector<char>& as_vector_char() {
return boost::get<std::vector<char> >(*this);
}
raw_ref const& as_raw_ref() const {
return boost::get<raw_ref>(*this);
}
ext const& as_ext() const {
return boost::get<ext>(*this);
}
ext& as_ext() {
return boost::get<ext>(*this);
}
ext_ref const& as_ext_ref() const {
return boost::get<ext_ref>(*this);
}
std::vector<basic_variant<STR, BIN, EXT> > const& as_vector() const {
return boost::get<std::vector<basic_variant<STR, BIN, EXT> > >(*this);
}
std::vector<basic_variant<STR, BIN, EXT> >& as_vector() {
return boost::get<std::vector<basic_variant<STR, BIN, EXT> > >(*this);
}
std::map<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > const& as_map() const {
return boost::get<std::map<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > >(*this);
}
std::map<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> >& as_map() {
return boost::get<std::map<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > >(*this);
}
std::multimap<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > const& as_multimap() const {
return boost::get<std::multimap<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > >(*this);
}
std::multimap<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> >& as_multimap() {
return boost::get<std::multimap<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > >(*this);
}
private:
template <typename T>
void int_init(T v) {
Expand All @@ -252,6 +237,19 @@ struct basic_variant :
static_cast<base&>(*this) = uint64_t(v);
}
}
void double_init(double v) {
if (v == v) { // check for nan
if (v >= 0 && v <= double(std::numeric_limits<uint64_t>::max()) && v == double(uint64_t(v))) {
static_cast<base&>(*this) = uint64_t(v);
return;
}
else if (v < 0 && v >= double(std::numeric_limits<int64_t>::min()) && v == double(int64_t(v))) {
static_cast<base&>(*this) = int64_t(v);
return;
}
}
static_cast<base&>(*this) = v;
}
};

template <typename STR, typename BIN, typename EXT>
Expand Down
8 changes: 4 additions & 4 deletions include/msgpack/v1/pack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1138,11 +1138,11 @@ inline packer<Stream>& packer<Stream>::pack_unsigned_long_long(unsigned long lon
template <typename Stream>
inline packer<Stream>& packer<Stream>::pack_float(float d)
{
if(d == d) { // check for nan
if(d == d) { // check for nan
// compare d to limits to avoid undefined behaviour
if(d >= 0 && d <= float(std::numeric_limits<uint64_t>::max()) && d == float(uint64_t(d))) {
pack_imp_uint64(uint64_t(d));
return *this;
return *this;
} else if(d < 0 && d >= float(std::numeric_limits<int64_t>::min()) && d == float(int64_t(d))) {
pack_imp_int64(int64_t(d));
return *this;
Expand All @@ -1160,11 +1160,11 @@ inline packer<Stream>& packer<Stream>::pack_float(float d)
template <typename Stream>
inline packer<Stream>& packer<Stream>::pack_double(double d)
{
if(d == d) { // check for nan
if(d == d) { // check for nan
// compare d to limits to avoid undefined behaviour
if(d >= 0 && d <= double(std::numeric_limits<uint64_t>::max()) && d == double(uint64_t(d))) {
pack_imp_uint64(uint64_t(d));
return *this;
return *this;
} else if(d < 0 && d >= double(std::numeric_limits<int64_t>::min()) && d == double(int64_t(d))) {
pack_imp_int64(int64_t(d));
return *this;
Expand Down
116 changes: 113 additions & 3 deletions test/boost_variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ BOOST_AUTO_TEST_CASE(pack_convert_variant_float)
BOOST_CHECK(val2.is_double());
BOOST_CHECK(fabs(12.34 - val2.as_double()) <= kEPS);
BOOST_CHECK_NO_THROW(boost::get<double>(val2));
BOOST_CHECK(fabs(val2.as_double() - val2.as_double()) <= kEPS);
BOOST_CHECK(fabs(val1.as_double() - val2.as_double()) <= kEPS);
}

BOOST_AUTO_TEST_CASE(object_variant_float)
Expand All @@ -277,7 +277,8 @@ BOOST_AUTO_TEST_CASE(object_variant_float)
BOOST_CHECK(val2.is_double());
BOOST_CHECK(fabs(12.34 - val2.as_double()) <= kEPS);
BOOST_CHECK_NO_THROW(boost::get<double>(val2));
BOOST_CHECK(fabs(val2.as_double() - val2.as_double()) <= kEPS);
BOOST_CHECK(fabs(val1.as_double() - val2.as_double()) <= kEPS);
BOOST_CHECK(val1 == val2);
}

BOOST_AUTO_TEST_CASE(object_with_zone_variant_float)
Expand All @@ -291,7 +292,116 @@ BOOST_AUTO_TEST_CASE(object_with_zone_variant_float)
BOOST_CHECK(val2.is_double());
BOOST_CHECK(fabs(12.34 - val2.as_double()) <= kEPS);
BOOST_CHECK_NO_THROW(boost::get<double>(val2));
BOOST_CHECK(fabs(val2.as_double() - val2.as_double()) <= kEPS);
BOOST_CHECK(fabs(val1.as_double() - val2.as_double()) <= kEPS);
BOOST_CHECK(val1 == val2);
}

BOOST_AUTO_TEST_CASE(pack_convert_variant_float_zero_atdp_positive)
{
std::stringstream ss;
msgpack::type::variant val1 = 12.0;
BOOST_CHECK(val1.is_uint64_t());
BOOST_CHECK_EQUAL(val1.as_uint64_t(), 12);
BOOST_CHECK(fabs(12.0 - val1.as_double()) <= kEPS);

msgpack::pack(ss, val1);

std::string const& str = ss.str();
msgpack::object_handle oh =
msgpack::unpack(str.data(), str.size());
msgpack::type::variant val2 = oh.get().as<msgpack::type::variant>();
BOOST_CHECK(val2.is_uint64_t());
BOOST_CHECK_EQUAL(val2.as_uint64_t(), 12);
BOOST_CHECK_NO_THROW(boost::get<uint64_t>(val2));
BOOST_CHECK(fabs(12.0 - val2.as_double()) <= kEPS);
BOOST_CHECK_EQUAL(val1.as_uint64_t(), val2.as_uint64_t());
}

BOOST_AUTO_TEST_CASE(object_variant_float_zero_atdp_positive)
{
msgpack::type::variant val1 = 12.0;
BOOST_CHECK(val1.is_uint64_t());
BOOST_CHECK_EQUAL(val1.as_uint64_t(), 12);
BOOST_CHECK(fabs(12.0 - val1.as_double()) <= kEPS);
msgpack::object obj(val1);
msgpack::type::variant val2 = obj.as<msgpack::type::variant>();
BOOST_CHECK(val2.is_uint64_t());
BOOST_CHECK_EQUAL(val2.as_uint64_t(), 12);
BOOST_CHECK_NO_THROW(boost::get<uint64_t>(val2));
BOOST_CHECK(fabs(12.0 - val2.as_double()) <= kEPS);
BOOST_CHECK_EQUAL(val1.as_uint64_t(), val2.as_uint64_t());
BOOST_CHECK(val1 == val2);
}

BOOST_AUTO_TEST_CASE(object_with_zone_variant_float_zero_atdp_positive)
{
msgpack::zone z;
msgpack::type::variant val1 = 12.0;
BOOST_CHECK(val1.is_uint64_t());
BOOST_CHECK_EQUAL(val1.as_uint64_t(), 12);
BOOST_CHECK(fabs(12.0 - val1.as_double()) <= kEPS);
msgpack::object obj(val1, z);
msgpack::type::variant val2 = obj.as<msgpack::type::variant>();
BOOST_CHECK(val2.is_uint64_t());
BOOST_CHECK_EQUAL(val2.as_uint64_t(), 12);
BOOST_CHECK_NO_THROW(boost::get<uint64_t>(val2));
BOOST_CHECK_EQUAL(val1.as_uint64_t(), val2.as_uint64_t());
BOOST_CHECK(fabs(12.0 - val2.as_double()) <= kEPS);
BOOST_CHECK(val1 == val2);
}

BOOST_AUTO_TEST_CASE(pack_convert_variant_float_zero_atdp_negative)
{
std::stringstream ss;
msgpack::type::variant val1 = -12.0;
BOOST_CHECK(val1.is_int64_t());
BOOST_CHECK_EQUAL(val1.as_int64_t(), -12);
BOOST_CHECK(fabs(-12.0 - val1.as_double()) <= kEPS);

msgpack::pack(ss, val1);

std::string const& str = ss.str();
msgpack::object_handle oh =
msgpack::unpack(str.data(), str.size());
msgpack::type::variant val2 = oh.get().as<msgpack::type::variant>();
BOOST_CHECK(val2.is_int64_t());
BOOST_CHECK_EQUAL(val2.as_int64_t(), -12);
BOOST_CHECK_NO_THROW(boost::get<int64_t>(val2));
BOOST_CHECK(fabs(-12.0 - val2.as_double()) <= kEPS);
BOOST_CHECK_EQUAL(val1.as_int64_t(), val2.as_int64_t());
}

BOOST_AUTO_TEST_CASE(object_variant_float_zero_atdp_negative)
{
msgpack::type::variant val1 = -12.0;
BOOST_CHECK(val1.is_int64_t());
BOOST_CHECK_EQUAL(val1.as_int64_t(), -12);
BOOST_CHECK(fabs(-12.0 - val1.as_double()) <= kEPS);
msgpack::object obj(val1);
msgpack::type::variant val2 = obj.as<msgpack::type::variant>();
BOOST_CHECK(val2.is_int64_t());
BOOST_CHECK_EQUAL(val2.as_int64_t(), -12);
BOOST_CHECK_NO_THROW(boost::get<int64_t>(val2));
BOOST_CHECK(fabs(-12.0 - val2.as_double()) <= kEPS);
BOOST_CHECK_EQUAL(val1.as_int64_t(), val2.as_int64_t());
BOOST_CHECK(val1 == val2);
}

BOOST_AUTO_TEST_CASE(object_with_zone_variant_float_zero_atdp_negative)
{
msgpack::zone z;
msgpack::type::variant val1 = -12.0;
BOOST_CHECK(val1.is_int64_t());
BOOST_CHECK_EQUAL(val1.as_int64_t(), -12);
BOOST_CHECK(fabs(-12.0 - val1.as_double()) <= kEPS);
msgpack::object obj(val1, z);
msgpack::type::variant val2 = obj.as<msgpack::type::variant>();
BOOST_CHECK(val2.is_int64_t());
BOOST_CHECK_EQUAL(val2.as_int64_t(), -12);
BOOST_CHECK_NO_THROW(boost::get<int64_t>(val2));
BOOST_CHECK(fabs(-12.0 - val2.as_double()) <= kEPS);
BOOST_CHECK_EQUAL(val1.as_int64_t(), val2.as_int64_t());
BOOST_CHECK(val1 == val2);
}

// str
Expand Down

0 comments on commit ac062e2

Please sign in to comment.