Skip to content

Commit 34f8fd6

Browse files
committed
Fixed msgpack#1070.
- msgpack::type::variant behaves as MessagePack format. e.g.) 12.34 => double 12.0 => uint64_t -12.34 => double -12.0 => int64_t - msgpack::type::variant::as_double() can be used even if interval type is int64_t and/or uint64_t. - msgpack::type::variant::as_*() don't return non const reference internal value. - fix coding style
1 parent 706fde4 commit 34f8fd6

File tree

3 files changed

+146
-38
lines changed

3 files changed

+146
-38
lines changed

include/msgpack/v1/adaptor/boost/msgpack_variant.hpp

+29-31
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ struct basic_variant :
122122
int_init(v);
123123
}
124124
basic_variant(unsigned long long v):base(uint64_t(v)) {}
125+
basic_variant(float v) {
126+
double_init(v);
127+
}
128+
basic_variant(double v) {
129+
double_init(v);
130+
}
125131

126132
bool is_nil() const {
127133
return boost::get<msgpack::type::nil_t>(this) != MSGPACK_NULLPTR;
@@ -177,71 +183,50 @@ struct basic_variant :
177183
int64_t as_int64_t() const {
178184
return boost::get<int64_t>(*this);
179185
}
180-
int64_t& as_int64_t() {
181-
return boost::get<int64_t>(*this);
182-
}
183186
uint64_t as_uint64_t() const {
184187
return boost::get<uint64_t>(*this);
185188
}
186-
uint64_t& as_uint64_t() {
187-
return boost::get<uint64_t>(*this);
188-
}
189189
double as_double() const {
190-
return boost::get<double>(*this);
191-
}
192-
double& as_double() {
193-
return boost::get<double>(*this);
190+
if (is_double()) {
191+
return boost::get<double>(*this);
192+
}
193+
if (is_int64_t()) {
194+
return static_cast<double>(boost::get<int64_t>(*this));
195+
}
196+
if (is_uint64_t()) {
197+
return static_cast<double>(boost::get<uint64_t>(*this));
198+
}
199+
throw msgpack::type_error();
194200
}
195201
std::string const& as_string() const {
196202
return boost::get<std::string>(*this);
197203
}
198-
std::string& as_string() {
199-
return boost::get<std::string>(*this);
200-
}
201204
#if (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53
202205
boost::string_ref const& as_boost_string_ref() const {
203206
return boost::get<boost::string_ref>(*this);
204207
}
205-
boost::string_ref& as_boost_string_ref() {
206-
return boost::get<boost::string_ref>(*this);
207-
}
208208
#endif // (BOOST_VERSION / 100000) >= 1 && ((BOOST_VERSION / 100) % 1000) >= 53
209209
std::vector<char> const& as_vector_char() const {
210210
return boost::get<std::vector<char> >(*this);
211211
}
212-
std::vector<char>& as_vector_char() {
213-
return boost::get<std::vector<char> >(*this);
214-
}
215212
raw_ref const& as_raw_ref() const {
216213
return boost::get<raw_ref>(*this);
217214
}
218215
ext const& as_ext() const {
219216
return boost::get<ext>(*this);
220217
}
221-
ext& as_ext() {
222-
return boost::get<ext>(*this);
223-
}
224218
ext_ref const& as_ext_ref() const {
225219
return boost::get<ext_ref>(*this);
226220
}
227221
std::vector<basic_variant<STR, BIN, EXT> > const& as_vector() const {
228222
return boost::get<std::vector<basic_variant<STR, BIN, EXT> > >(*this);
229223
}
230-
std::vector<basic_variant<STR, BIN, EXT> >& as_vector() {
231-
return boost::get<std::vector<basic_variant<STR, BIN, EXT> > >(*this);
232-
}
233224
std::map<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > const& as_map() const {
234225
return boost::get<std::map<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > >(*this);
235226
}
236-
std::map<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> >& as_map() {
237-
return boost::get<std::map<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > >(*this);
238-
}
239227
std::multimap<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > const& as_multimap() const {
240228
return boost::get<std::multimap<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > >(*this);
241229
}
242-
std::multimap<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> >& as_multimap() {
243-
return boost::get<std::multimap<basic_variant<STR, BIN, EXT>, basic_variant<STR, BIN, EXT> > >(*this);
244-
}
245230
private:
246231
template <typename T>
247232
void int_init(T v) {
@@ -252,6 +237,19 @@ struct basic_variant :
252237
static_cast<base&>(*this) = uint64_t(v);
253238
}
254239
}
240+
void double_init(double v) {
241+
if (v == v) { // check for nan
242+
if (v >= 0 && v <= double(std::numeric_limits<uint64_t>::max()) && v == double(uint64_t(v))) {
243+
static_cast<base&>(*this) = uint64_t(v);
244+
return;
245+
}
246+
else if (v < 0 && v >= double(std::numeric_limits<int64_t>::min()) && v == double(int64_t(v))) {
247+
static_cast<base&>(*this) = int64_t(v);
248+
return;
249+
}
250+
}
251+
static_cast<base&>(*this) = v;
252+
}
255253
};
256254

257255
template <typename STR, typename BIN, typename EXT>

include/msgpack/v1/pack.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -1138,11 +1138,11 @@ inline packer<Stream>& packer<Stream>::pack_unsigned_long_long(unsigned long lon
11381138
template <typename Stream>
11391139
inline packer<Stream>& packer<Stream>::pack_float(float d)
11401140
{
1141-
if(d == d) { // check for nan
1141+
if(d == d) { // check for nan
11421142
// compare d to limits to avoid undefined behaviour
11431143
if(d >= 0 && d <= float(std::numeric_limits<uint64_t>::max()) && d == float(uint64_t(d))) {
11441144
pack_imp_uint64(uint64_t(d));
1145-
return *this;
1145+
return *this;
11461146
} else if(d < 0 && d >= float(std::numeric_limits<int64_t>::min()) && d == float(int64_t(d))) {
11471147
pack_imp_int64(int64_t(d));
11481148
return *this;
@@ -1160,11 +1160,11 @@ inline packer<Stream>& packer<Stream>::pack_float(float d)
11601160
template <typename Stream>
11611161
inline packer<Stream>& packer<Stream>::pack_double(double d)
11621162
{
1163-
if(d == d) { // check for nan
1163+
if(d == d) { // check for nan
11641164
// compare d to limits to avoid undefined behaviour
11651165
if(d >= 0 && d <= double(std::numeric_limits<uint64_t>::max()) && d == double(uint64_t(d))) {
11661166
pack_imp_uint64(uint64_t(d));
1167-
return *this;
1167+
return *this;
11681168
} else if(d < 0 && d >= double(std::numeric_limits<int64_t>::min()) && d == double(int64_t(d))) {
11691169
pack_imp_int64(int64_t(d));
11701170
return *this;

test/boost_variant.cpp

+113-3
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ BOOST_AUTO_TEST_CASE(pack_convert_variant_float)
264264
BOOST_CHECK(val2.is_double());
265265
BOOST_CHECK(fabs(12.34 - val2.as_double()) <= kEPS);
266266
BOOST_CHECK_NO_THROW(boost::get<double>(val2));
267-
BOOST_CHECK(fabs(val2.as_double() - val2.as_double()) <= kEPS);
267+
BOOST_CHECK(fabs(val1.as_double() - val2.as_double()) <= kEPS);
268268
}
269269

270270
BOOST_AUTO_TEST_CASE(object_variant_float)
@@ -277,7 +277,8 @@ BOOST_AUTO_TEST_CASE(object_variant_float)
277277
BOOST_CHECK(val2.is_double());
278278
BOOST_CHECK(fabs(12.34 - val2.as_double()) <= kEPS);
279279
BOOST_CHECK_NO_THROW(boost::get<double>(val2));
280-
BOOST_CHECK(fabs(val2.as_double() - val2.as_double()) <= kEPS);
280+
BOOST_CHECK(fabs(val1.as_double() - val2.as_double()) <= kEPS);
281+
BOOST_CHECK(val1 == val2);
281282
}
282283

283284
BOOST_AUTO_TEST_CASE(object_with_zone_variant_float)
@@ -291,7 +292,116 @@ BOOST_AUTO_TEST_CASE(object_with_zone_variant_float)
291292
BOOST_CHECK(val2.is_double());
292293
BOOST_CHECK(fabs(12.34 - val2.as_double()) <= kEPS);
293294
BOOST_CHECK_NO_THROW(boost::get<double>(val2));
294-
BOOST_CHECK(fabs(val2.as_double() - val2.as_double()) <= kEPS);
295+
BOOST_CHECK(fabs(val1.as_double() - val2.as_double()) <= kEPS);
296+
BOOST_CHECK(val1 == val2);
297+
}
298+
299+
BOOST_AUTO_TEST_CASE(pack_convert_variant_float_zero_atdp_positive)
300+
{
301+
std::stringstream ss;
302+
msgpack::type::variant val1 = 12.0;
303+
BOOST_CHECK(val1.is_uint64_t());
304+
BOOST_CHECK_EQUAL(val1.as_uint64_t(), 12);
305+
BOOST_CHECK(fabs(12.0 - val1.as_double()) <= kEPS);
306+
307+
msgpack::pack(ss, val1);
308+
309+
std::string const& str = ss.str();
310+
msgpack::object_handle oh =
311+
msgpack::unpack(str.data(), str.size());
312+
msgpack::type::variant val2 = oh.get().as<msgpack::type::variant>();
313+
BOOST_CHECK(val2.is_uint64_t());
314+
BOOST_CHECK_EQUAL(val2.as_uint64_t(), 12);
315+
BOOST_CHECK_NO_THROW(boost::get<uint64_t>(val2));
316+
BOOST_CHECK(fabs(12.0 - val2.as_double()) <= kEPS);
317+
BOOST_CHECK_EQUAL(val1.as_uint64_t(), val2.as_uint64_t());
318+
}
319+
320+
BOOST_AUTO_TEST_CASE(object_variant_float_zero_atdp_positive)
321+
{
322+
msgpack::type::variant val1 = 12.0;
323+
BOOST_CHECK(val1.is_uint64_t());
324+
BOOST_CHECK_EQUAL(val1.as_uint64_t(), 12);
325+
BOOST_CHECK(fabs(12.0 - val1.as_double()) <= kEPS);
326+
msgpack::object obj(val1);
327+
msgpack::type::variant val2 = obj.as<msgpack::type::variant>();
328+
BOOST_CHECK(val2.is_uint64_t());
329+
BOOST_CHECK_EQUAL(val2.as_uint64_t(), 12);
330+
BOOST_CHECK_NO_THROW(boost::get<uint64_t>(val2));
331+
BOOST_CHECK(fabs(12.0 - val2.as_double()) <= kEPS);
332+
BOOST_CHECK_EQUAL(val1.as_uint64_t(), val2.as_uint64_t());
333+
BOOST_CHECK(val1 == val2);
334+
}
335+
336+
BOOST_AUTO_TEST_CASE(object_with_zone_variant_float_zero_atdp_positive)
337+
{
338+
msgpack::zone z;
339+
msgpack::type::variant val1 = 12.0;
340+
BOOST_CHECK(val1.is_uint64_t());
341+
BOOST_CHECK_EQUAL(val1.as_uint64_t(), 12);
342+
BOOST_CHECK(fabs(12.0 - val1.as_double()) <= kEPS);
343+
msgpack::object obj(val1, z);
344+
msgpack::type::variant val2 = obj.as<msgpack::type::variant>();
345+
BOOST_CHECK(val2.is_uint64_t());
346+
BOOST_CHECK_EQUAL(val2.as_uint64_t(), 12);
347+
BOOST_CHECK_NO_THROW(boost::get<uint64_t>(val2));
348+
BOOST_CHECK_EQUAL(val1.as_uint64_t(), val2.as_uint64_t());
349+
BOOST_CHECK(fabs(12.0 - val2.as_double()) <= kEPS);
350+
BOOST_CHECK(val1 == val2);
351+
}
352+
353+
BOOST_AUTO_TEST_CASE(pack_convert_variant_float_zero_atdp_negative)
354+
{
355+
std::stringstream ss;
356+
msgpack::type::variant val1 = -12.0;
357+
BOOST_CHECK(val1.is_int64_t());
358+
BOOST_CHECK_EQUAL(val1.as_int64_t(), -12);
359+
BOOST_CHECK(fabs(-12.0 - val1.as_double()) <= kEPS);
360+
361+
msgpack::pack(ss, val1);
362+
363+
std::string const& str = ss.str();
364+
msgpack::object_handle oh =
365+
msgpack::unpack(str.data(), str.size());
366+
msgpack::type::variant val2 = oh.get().as<msgpack::type::variant>();
367+
BOOST_CHECK(val2.is_int64_t());
368+
BOOST_CHECK_EQUAL(val2.as_int64_t(), -12);
369+
BOOST_CHECK_NO_THROW(boost::get<int64_t>(val2));
370+
BOOST_CHECK(fabs(-12.0 - val2.as_double()) <= kEPS);
371+
BOOST_CHECK_EQUAL(val1.as_int64_t(), val2.as_int64_t());
372+
}
373+
374+
BOOST_AUTO_TEST_CASE(object_variant_float_zero_atdp_negative)
375+
{
376+
msgpack::type::variant val1 = -12.0;
377+
BOOST_CHECK(val1.is_int64_t());
378+
BOOST_CHECK_EQUAL(val1.as_int64_t(), -12);
379+
BOOST_CHECK(fabs(-12.0 - val1.as_double()) <= kEPS);
380+
msgpack::object obj(val1);
381+
msgpack::type::variant val2 = obj.as<msgpack::type::variant>();
382+
BOOST_CHECK(val2.is_int64_t());
383+
BOOST_CHECK_EQUAL(val2.as_int64_t(), -12);
384+
BOOST_CHECK_NO_THROW(boost::get<int64_t>(val2));
385+
BOOST_CHECK(fabs(-12.0 - val2.as_double()) <= kEPS);
386+
BOOST_CHECK_EQUAL(val1.as_int64_t(), val2.as_int64_t());
387+
BOOST_CHECK(val1 == val2);
388+
}
389+
390+
BOOST_AUTO_TEST_CASE(object_with_zone_variant_float_zero_atdp_negative)
391+
{
392+
msgpack::zone z;
393+
msgpack::type::variant val1 = -12.0;
394+
BOOST_CHECK(val1.is_int64_t());
395+
BOOST_CHECK_EQUAL(val1.as_int64_t(), -12);
396+
BOOST_CHECK(fabs(-12.0 - val1.as_double()) <= kEPS);
397+
msgpack::object obj(val1, z);
398+
msgpack::type::variant val2 = obj.as<msgpack::type::variant>();
399+
BOOST_CHECK(val2.is_int64_t());
400+
BOOST_CHECK_EQUAL(val2.as_int64_t(), -12);
401+
BOOST_CHECK_NO_THROW(boost::get<int64_t>(val2));
402+
BOOST_CHECK(fabs(-12.0 - val2.as_double()) <= kEPS);
403+
BOOST_CHECK_EQUAL(val1.as_int64_t(), val2.as_int64_t());
404+
BOOST_CHECK(val1 == val2);
295405
}
296406

297407
// str

0 commit comments

Comments
 (0)