Skip to content

Commit e8eeab8

Browse files
committed
Fixed msgpack#1087 for C++.
Treat signaling NaN correctly.
1 parent b2f056c commit e8eeab8

File tree

10 files changed

+415
-1
lines changed

10 files changed

+415
-1
lines changed

Files.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ SET (msgpack-cxx_HEADERS
8282
include/msgpack/iterator_decl.hpp
8383
include/msgpack/meta.hpp
8484
include/msgpack/meta_decl.hpp
85+
include/msgpack/nan_util.hpp
8586
include/msgpack/null_visitor.hpp
8687
include/msgpack/null_visitor_decl.hpp
8788
include/msgpack/object.hpp
@@ -604,6 +605,7 @@ SET (msgpack-cxx_HEADERS
604605
include/msgpack/v1/iterator_decl.hpp
605606
include/msgpack/v1/meta.hpp
606607
include/msgpack/v1/meta_decl.hpp
608+
include/msgpack/v1/nan_util.hpp
607609
include/msgpack/v1/object.hpp
608610
include/msgpack/v1/object_decl.hpp
609611
include/msgpack/v1/object_fwd.hpp
@@ -653,6 +655,7 @@ SET (msgpack-cxx_HEADERS
653655
include/msgpack/v2/fbuffer_decl.hpp
654656
include/msgpack/v2/iterator_decl.hpp
655657
include/msgpack/v2/meta_decl.hpp
658+
include/msgpack/v2/nan_util.hpp
656659
include/msgpack/v2/null_visitor.hpp
657660
include/msgpack/v2/null_visitor_decl.hpp
658661
include/msgpack/v2/object.hpp
@@ -701,6 +704,7 @@ SET (msgpack-cxx_HEADERS
701704
include/msgpack/v3/fbuffer_decl.hpp
702705
include/msgpack/v3/iterator_decl.hpp
703706
include/msgpack/v3/meta_decl.hpp
707+
include/msgpack/v3/nan_util.hpp
704708
include/msgpack/v3/null_visitor_decl.hpp
705709
include/msgpack/v3/object_decl.hpp
706710
include/msgpack/v3/object_fwd.hpp

include/msgpack/nan_util.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// MessagePack for C++ NaN utility
3+
//
4+
// Copyright (C) 2023 KONDO Takatoshi
5+
//
6+
// Distributed under the Boost Software License, Version 1.0.
7+
// (See accompanying file LICENSE_1_0.txt or copy at
8+
// http://www.boost.org/LICENSE_1_0.txt)
9+
//
10+
#ifndef MSGPACK_NAN_UTIL_HPP
11+
#define MSGPACK_NAN_UTIL_HPP
12+
13+
#include "msgpack/v1/nan_util.hpp"
14+
#include "msgpack/v2/nan_util.hpp"
15+
#include "msgpack/v3/nan_util.hpp"
16+
17+
#endif // MSGPACK_NAN_UTIL_HPP

include/msgpack/v1/adaptor/float.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ struct convert<float> {
2929
msgpack::object const& operator()(msgpack::object const& o, float& v) const {
3030
if(o.type == msgpack::type::FLOAT32 || o.type == msgpack::type::FLOAT64) {
3131
v = static_cast<float>(o.via.f64);
32+
if (o.via.f64 != o.via.f64) { // nan
33+
if (!is_quiet_nan(o.via.f64)) { // signaling
34+
clear_quiet(v);
35+
}
36+
}
3237
}
3338
else if (o.type == msgpack::type::POSITIVE_INTEGER) {
3439
v = static_cast<float>(o.via.u64);
@@ -87,6 +92,11 @@ struct object<float> {
8792
void operator()(msgpack::object& o, float v) const {
8893
o.type = msgpack::type::FLOAT32;
8994
o.via.f64 = static_cast<double>(v);
95+
if (v != v) { // nan
96+
if (!is_quiet_nan(v)) { // signaling
97+
clear_quiet(o.via.f64);
98+
}
99+
}
90100
}
91101
};
92102

include/msgpack/v1/nan_util.hpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//
2+
// MessagePack for C++ NaN utility
3+
//
4+
// Copyright (C) 2023 KONDO Takatoshi
5+
//
6+
// Distributed under the Boost Software License, Version 1.0.
7+
// (See accompanying file LICENSE_1_0.txt or copy at
8+
// http://www.boost.org/LICENSE_1_0.txt)
9+
//
10+
#ifndef MSGPACK_V1_NAN_UTIL_HPP
11+
#define MSGPACK_V1_NAN_UTIL_HPP
12+
13+
#include <limits>
14+
#include <cfloat>
15+
#include <cmath>
16+
#include <cstdint>
17+
18+
#include <msgpack/assert.hpp>
19+
20+
namespace msgpack {
21+
22+
/// @cond
23+
MSGPACK_API_VERSION_NAMESPACE(v1) {
24+
/// @endcond
25+
26+
inline bool is_quiet_nan(double const& nan_val) {
27+
MSGPACK_ASSERT(nan_val != nan_val);
28+
uint64_t bit_pattern = reinterpret_cast<uint64_t const&>(nan_val);
29+
int is_quiet_bit_index = DBL_MANT_DIG - 2;
30+
return (bit_pattern >> is_quiet_bit_index) & 1;
31+
}
32+
33+
inline bool is_quiet_nan(float const& nan_val) {
34+
MSGPACK_ASSERT(nan_val != nan_val);
35+
uint32_t bit_pattern = reinterpret_cast<uint32_t const&>(nan_val);
36+
int is_quiet_bit_index = FLT_MANT_DIG - 2;
37+
return (bit_pattern >> is_quiet_bit_index) & 1;
38+
}
39+
40+
inline void clear_quiet(double& nan_val) {
41+
MSGPACK_ASSERT(nan_val != nan_val);
42+
int is_quiet_bit_index = DBL_MANT_DIG - 2;
43+
uint64_t mask = uint64_t(1) << is_quiet_bit_index;
44+
reinterpret_cast<uint64_t&>(nan_val) &= ~mask;
45+
}
46+
47+
inline void clear_quiet(float& nan_val) {
48+
MSGPACK_ASSERT(nan_val != nan_val);
49+
int is_quiet_bit_index = FLT_MANT_DIG - 2;
50+
uint64_t mask = uint64_t(1) << is_quiet_bit_index;
51+
reinterpret_cast<uint32_t&>(nan_val) &= ~mask;
52+
}
53+
54+
/// @cond
55+
} // MSGPACK_API_VERSION_NAMESPACE(v1)
56+
/// @endcond
57+
58+
} // namespace msgpack
59+
60+
#endif // MSGPACK_V1_NAN_UTIL_HPP

include/msgpack/v1/unpack.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "msgpack/cpp_config.hpp"
2020
#include "msgpack/sysdep.hpp"
2121
#include "msgpack/assert.hpp"
22+
#include "msgpack/nan_util.hpp"
2223

2324
#include <memory>
2425

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

9798
inline void unpack_float(float d, msgpack::object& o)
98-
{ o.type = msgpack::type::FLOAT32; o.via.f64 = d; }
99+
{
100+
o.type = msgpack::type::FLOAT32;
101+
o.via.f64 = d;
102+
if (d != d) { // nan
103+
if (!is_quiet_nan(d)) { // signaling NaN
104+
clear_quiet(o.via.f64); // becomes signaling
105+
}
106+
}
107+
}
99108

100109
inline void unpack_double(double d, msgpack::object& o)
101110
{ o.type = msgpack::type::FLOAT64; o.via.f64 = d; }

include/msgpack/v2/create_object_visitor.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "msgpack/v2/create_object_visitor_decl.hpp"
1616
#include "msgpack/v2/null_visitor.hpp"
1717
#include "msgpack/assert.hpp"
18+
#include "msgpack/nan_util.hpp"
1819

1920
namespace msgpack {
2021

@@ -98,6 +99,11 @@ class create_object_visitor : public msgpack::v2::null_visitor {
9899
msgpack::object* obj = m_stack.back();
99100
obj->type = msgpack::type::FLOAT32;
100101
obj->via.f64 = v;
102+
if (v != v) { // nan
103+
if (!is_quiet_nan(v)) { // signaling NaN
104+
clear_quiet(obj->via.f64); // becomes signaling
105+
}
106+
}
101107
return true;
102108
}
103109
bool visit_float64(double v) {

include/msgpack/v2/nan_util.hpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// MessagePack for C++ NaN utility
3+
//
4+
// Copyright (C) 2023 KONDO Takatoshi
5+
//
6+
// Distributed under the Boost Software License, Version 1.0.
7+
// (See accompanying file LICENSE_1_0.txt or copy at
8+
// http://www.boost.org/LICENSE_1_0.txt)
9+
//
10+
#ifndef MSGPACK_V2_NAN_UTIL_HPP
11+
#define MSGPACK_V2_NAN_UTIL_HPP
12+
13+
#include "msgpack/v1/nan_util.hpp"
14+
15+
16+
namespace msgpack {
17+
18+
/// @cond
19+
MSGPACK_API_VERSION_NAMESPACE(v2) {
20+
/// @endcond
21+
22+
using v1::is_quiet_nan;
23+
using v1::clear_quiet;
24+
25+
/// @cond
26+
} // MSGPACK_API_VERSION_NAMESPACE(v2)
27+
/// @endcond
28+
29+
} // namespace msgpack
30+
31+
#endif // MSGPACK_V2_NAN_UTIL_HPP

include/msgpack/v3/nan_util.hpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// MessagePack for C++ NaN utility
3+
//
4+
// Copyright (C) 2023 KONDO Takatoshi
5+
//
6+
// Distributed under the Boost Software License, Version 1.0.
7+
// (See accompanying file LICENSE_1_0.txt or copy at
8+
// http://www.boost.org/LICENSE_1_0.txt)
9+
//
10+
#ifndef MSGPACK_V3_NAN_UTIL_HPP
11+
#define MSGPACK_V3_NAN_UTIL_HPP
12+
13+
#include "msgpack/v2/nan_util.hpp"
14+
15+
16+
namespace msgpack {
17+
18+
/// @cond
19+
MSGPACK_API_VERSION_NAMESPACE(v3) {
20+
/// @endcond
21+
22+
using v2::is_quiet_nan;
23+
using v2::clear_quiet;
24+
25+
/// @cond
26+
} // MSGPACK_API_VERSION_NAMESPACE(v3)
27+
/// @endcond
28+
29+
} // namespace msgpack
30+
31+
#endif // MSGPACK_V3_NAN_UTIL_HPP

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ LIST (APPEND check_PROGRAMS
2222
msgpack_stream.cpp
2323
msgpack_tuple.cpp
2424
msgpack_vref.cpp
25+
nan.cpp
2526
object.cpp
2627
object_with_zone.cpp
2728
pack_unpack.cpp

0 commit comments

Comments
 (0)