Skip to content

Commit

Permalink
Fixed msgpack#1087 for C++.
Browse files Browse the repository at this point in the history
Treat signaling NaN correctly.
  • Loading branch information
redboltz committed Aug 28, 2023
1 parent b2f056c commit e8eeab8
Show file tree
Hide file tree
Showing 10 changed files with 415 additions and 1 deletion.
4 changes: 4 additions & 0 deletions Files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ SET (msgpack-cxx_HEADERS
include/msgpack/iterator_decl.hpp
include/msgpack/meta.hpp
include/msgpack/meta_decl.hpp
include/msgpack/nan_util.hpp
include/msgpack/null_visitor.hpp
include/msgpack/null_visitor_decl.hpp
include/msgpack/object.hpp
Expand Down Expand Up @@ -604,6 +605,7 @@ SET (msgpack-cxx_HEADERS
include/msgpack/v1/iterator_decl.hpp
include/msgpack/v1/meta.hpp
include/msgpack/v1/meta_decl.hpp
include/msgpack/v1/nan_util.hpp
include/msgpack/v1/object.hpp
include/msgpack/v1/object_decl.hpp
include/msgpack/v1/object_fwd.hpp
Expand Down Expand Up @@ -653,6 +655,7 @@ SET (msgpack-cxx_HEADERS
include/msgpack/v2/fbuffer_decl.hpp
include/msgpack/v2/iterator_decl.hpp
include/msgpack/v2/meta_decl.hpp
include/msgpack/v2/nan_util.hpp
include/msgpack/v2/null_visitor.hpp
include/msgpack/v2/null_visitor_decl.hpp
include/msgpack/v2/object.hpp
Expand Down Expand Up @@ -701,6 +704,7 @@ SET (msgpack-cxx_HEADERS
include/msgpack/v3/fbuffer_decl.hpp
include/msgpack/v3/iterator_decl.hpp
include/msgpack/v3/meta_decl.hpp
include/msgpack/v3/nan_util.hpp
include/msgpack/v3/null_visitor_decl.hpp
include/msgpack/v3/object_decl.hpp
include/msgpack/v3/object_fwd.hpp
Expand Down
17 changes: 17 additions & 0 deletions include/msgpack/nan_util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// MessagePack for C++ NaN utility
//
// Copyright (C) 2023 KONDO Takatoshi
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef MSGPACK_NAN_UTIL_HPP
#define MSGPACK_NAN_UTIL_HPP

#include "msgpack/v1/nan_util.hpp"
#include "msgpack/v2/nan_util.hpp"
#include "msgpack/v3/nan_util.hpp"

#endif // MSGPACK_NAN_UTIL_HPP
10 changes: 10 additions & 0 deletions include/msgpack/v1/adaptor/float.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ struct convert<float> {
msgpack::object const& operator()(msgpack::object const& o, float& v) const {
if(o.type == msgpack::type::FLOAT32 || o.type == msgpack::type::FLOAT64) {
v = static_cast<float>(o.via.f64);
if (o.via.f64 != o.via.f64) { // nan
if (!is_quiet_nan(o.via.f64)) { // signaling
clear_quiet(v);
}
}
}
else if (o.type == msgpack::type::POSITIVE_INTEGER) {
v = static_cast<float>(o.via.u64);
Expand Down Expand Up @@ -87,6 +92,11 @@ struct object<float> {
void operator()(msgpack::object& o, float v) const {
o.type = msgpack::type::FLOAT32;
o.via.f64 = static_cast<double>(v);
if (v != v) { // nan
if (!is_quiet_nan(v)) { // signaling
clear_quiet(o.via.f64);
}
}
}
};

Expand Down
60 changes: 60 additions & 0 deletions include/msgpack/v1/nan_util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// MessagePack for C++ NaN utility
//
// Copyright (C) 2023 KONDO Takatoshi
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef MSGPACK_V1_NAN_UTIL_HPP
#define MSGPACK_V1_NAN_UTIL_HPP

#include <limits>
#include <cfloat>
#include <cmath>
#include <cstdint>

#include <msgpack/assert.hpp>

namespace msgpack {

/// @cond
MSGPACK_API_VERSION_NAMESPACE(v1) {
/// @endcond

inline bool is_quiet_nan(double const& nan_val) {
MSGPACK_ASSERT(nan_val != nan_val);
uint64_t bit_pattern = reinterpret_cast<uint64_t const&>(nan_val);
int is_quiet_bit_index = DBL_MANT_DIG - 2;
return (bit_pattern >> is_quiet_bit_index) & 1;
}

inline bool is_quiet_nan(float const& nan_val) {
MSGPACK_ASSERT(nan_val != nan_val);
uint32_t bit_pattern = reinterpret_cast<uint32_t const&>(nan_val);
int is_quiet_bit_index = FLT_MANT_DIG - 2;
return (bit_pattern >> is_quiet_bit_index) & 1;
}

inline void clear_quiet(double& nan_val) {
MSGPACK_ASSERT(nan_val != nan_val);
int is_quiet_bit_index = DBL_MANT_DIG - 2;
uint64_t mask = uint64_t(1) << is_quiet_bit_index;
reinterpret_cast<uint64_t&>(nan_val) &= ~mask;
}

inline void clear_quiet(float& nan_val) {
MSGPACK_ASSERT(nan_val != nan_val);
int is_quiet_bit_index = FLT_MANT_DIG - 2;
uint64_t mask = uint64_t(1) << is_quiet_bit_index;
reinterpret_cast<uint32_t&>(nan_val) &= ~mask;
}

/// @cond
} // MSGPACK_API_VERSION_NAMESPACE(v1)
/// @endcond

} // namespace msgpack

#endif // MSGPACK_V1_NAN_UTIL_HPP
11 changes: 10 additions & 1 deletion include/msgpack/v1/unpack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "msgpack/cpp_config.hpp"
#include "msgpack/sysdep.hpp"
#include "msgpack/assert.hpp"
#include "msgpack/nan_util.hpp"

#include <memory>

Expand Down Expand Up @@ -95,7 +96,15 @@ inline void unpack_int64(int64_t d, msgpack::object& o)
else { o.type = msgpack::type::NEGATIVE_INTEGER; o.via.i64 = d; } }

inline void unpack_float(float d, msgpack::object& o)
{ o.type = msgpack::type::FLOAT32; o.via.f64 = d; }
{
o.type = msgpack::type::FLOAT32;
o.via.f64 = d;
if (d != d) { // nan
if (!is_quiet_nan(d)) { // signaling NaN
clear_quiet(o.via.f64); // becomes signaling
}
}
}

inline void unpack_double(double d, msgpack::object& o)
{ o.type = msgpack::type::FLOAT64; o.via.f64 = d; }
Expand Down
6 changes: 6 additions & 0 deletions include/msgpack/v2/create_object_visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "msgpack/v2/create_object_visitor_decl.hpp"
#include "msgpack/v2/null_visitor.hpp"
#include "msgpack/assert.hpp"
#include "msgpack/nan_util.hpp"

namespace msgpack {

Expand Down Expand Up @@ -98,6 +99,11 @@ class create_object_visitor : public msgpack::v2::null_visitor {
msgpack::object* obj = m_stack.back();
obj->type = msgpack::type::FLOAT32;
obj->via.f64 = v;
if (v != v) { // nan
if (!is_quiet_nan(v)) { // signaling NaN
clear_quiet(obj->via.f64); // becomes signaling
}
}
return true;
}
bool visit_float64(double v) {
Expand Down
31 changes: 31 additions & 0 deletions include/msgpack/v2/nan_util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// MessagePack for C++ NaN utility
//
// Copyright (C) 2023 KONDO Takatoshi
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef MSGPACK_V2_NAN_UTIL_HPP
#define MSGPACK_V2_NAN_UTIL_HPP

#include "msgpack/v1/nan_util.hpp"


namespace msgpack {

/// @cond
MSGPACK_API_VERSION_NAMESPACE(v2) {
/// @endcond

using v1::is_quiet_nan;
using v1::clear_quiet;

/// @cond
} // MSGPACK_API_VERSION_NAMESPACE(v2)
/// @endcond

} // namespace msgpack

#endif // MSGPACK_V2_NAN_UTIL_HPP
31 changes: 31 additions & 0 deletions include/msgpack/v3/nan_util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// MessagePack for C++ NaN utility
//
// Copyright (C) 2023 KONDO Takatoshi
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef MSGPACK_V3_NAN_UTIL_HPP
#define MSGPACK_V3_NAN_UTIL_HPP

#include "msgpack/v2/nan_util.hpp"


namespace msgpack {

/// @cond
MSGPACK_API_VERSION_NAMESPACE(v3) {
/// @endcond

using v2::is_quiet_nan;
using v2::clear_quiet;

/// @cond
} // MSGPACK_API_VERSION_NAMESPACE(v3)
/// @endcond

} // namespace msgpack

#endif // MSGPACK_V3_NAN_UTIL_HPP
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ LIST (APPEND check_PROGRAMS
msgpack_stream.cpp
msgpack_tuple.cpp
msgpack_vref.cpp
nan.cpp
object.cpp
object_with_zone.cpp
pack_unpack.cpp
Expand Down
Loading

0 comments on commit e8eeab8

Please sign in to comment.