diff --git a/include/msgpack/v1/pack.hpp b/include/msgpack/v1/pack.hpp index 677c39fa1..302d21358 100644 --- a/include/msgpack/v1/pack.hpp +++ b/include/msgpack/v1/pack.hpp @@ -257,6 +257,28 @@ class packer { */ packer& pack_fix_int64(int64_t d); + /// Packing float (fixed packed type). + /** + * The packed type is always float32. + * See https://github.com/msgpack/msgpack/blob/master/spec.md#formats-float + * + * @param d a packing object. + * + * @return The reference of `*this`. + */ + packer& pack_fix_float(float d); + + /// Packing double (fixed packed type). + /** + * The packed type is always float64. + * See https://github.com/msgpack/msgpack/blob/master/spec.md#formats-float + * + * @param d a packing object. + * + * @return The reference of `*this`. + */ + packer& pack_fix_double(double d); + /// Packing char /** @@ -827,6 +849,36 @@ inline packer& packer::pack_fix_int64(int64_t d) return *this; } +template +inline packer& packer::pack_fix_float(float d) +{ + union { float f; uint32_t i; } mem; + mem.f = d; + char buf[5]; + buf[0] = static_cast(0xcau); _msgpack_store32(&buf[1], mem.i); + append_buffer(buf, 5); + return *this; +} + +template +inline packer& packer::pack_fix_double(double d) +{ + union { double f; uint64_t i; } mem; + mem.f = d; + char buf[9]; + buf[0] = static_cast(0xcbu); + +#if defined(TARGET_OS_IPHONE) + // ok +#elif defined(__arm__) && !(__ARM_EABI__) // arm-oabi + // https://github.com/msgpack/msgpack-perl/pull/1 + mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL); +#endif + _msgpack_store64(&buf[1], mem.i); + append_buffer(buf, 9); + return *this; +} + template inline packer& packer::pack_char(char d) diff --git a/test/msgpack_basic.cpp b/test/msgpack_basic.cpp index 24b2a31fc..4a676a9bb 100644 --- a/test/msgpack_basic.cpp +++ b/test/msgpack_basic.cpp @@ -189,6 +189,49 @@ BOOST_AUTO_TEST_CASE(simple_buffer_float) } } +BOOST_AUTO_TEST_CASE(simple_buffer_pack_fix_float) +{ + vector v; + v.push_back(0.0); + v.push_back(-0.0); + v.push_back(1.0); + v.push_back(-1.0); + v.push_back(numeric_limits::min()); + v.push_back(numeric_limits::max()); + v.push_back(nanf("tag")); + if (numeric_limits::has_infinity) { + v.push_back(numeric_limits::infinity()); + v.push_back(-numeric_limits::infinity()); + } + if (numeric_limits::has_quiet_NaN) { + v.push_back(numeric_limits::quiet_NaN()); + } + if (numeric_limits::has_signaling_NaN) { + v.push_back(numeric_limits::signaling_NaN()); + } + + for (unsigned int i = 0; i < kLoop; i++) { + v.push_back(static_cast(msgpack_rand())); + v.push_back(static_cast(-msgpack_rand())); + } + for (unsigned int i = 0; i < v.size() ; i++) { + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + float val1 = v[i]; + packer.pack_fix_float(val1); + msgpack::object_handle oh = + msgpack::unpack(sbuf.data(), sbuf.size()); + float val2 = oh.get().as(); + + if (std::isnan(val1)) + BOOST_CHECK(std::isnan(val2)); + else if (std::isinf(val1)) + BOOST_CHECK(std::isinf(val2)); + else + BOOST_CHECK(fabs(val2 - val1) <= kEPS); + } +} + #endif // !defined(_MSC_VER) || _MSC_VER >=1800 namespace { @@ -275,6 +318,53 @@ BOOST_AUTO_TEST_CASE(simple_buffer_double) } } +BOOST_AUTO_TEST_CASE(simple_buffer_pack_fix_double) +{ + vector v; + v.push_back(0.0); + v.push_back(-0.0); + v.push_back(1.0); + v.push_back(-1.0); + v.push_back(numeric_limits::min()); + v.push_back(numeric_limits::max()); + v.push_back(nanf("tag")); + if (numeric_limits::has_infinity) { + v.push_back(numeric_limits::infinity()); + v.push_back(-numeric_limits::infinity()); + } + if (numeric_limits::has_quiet_NaN) { + v.push_back(numeric_limits::quiet_NaN()); + } + if (numeric_limits::has_signaling_NaN) { + v.push_back(numeric_limits::signaling_NaN()); + } + for (unsigned int i = 0; i < kLoop; i++) { + v.push_back(msgpack_rand()); + v.push_back(-msgpack_rand()); + } + + for (unsigned int i = 0; i < kLoop; i++) { + v.push_back(msgpack_rand()); + v.push_back(-msgpack_rand()); + } + for (unsigned int i = 0; i < v.size() ; i++) { + msgpack::sbuffer sbuf; + msgpack::packer packer(sbuf); + double val1 = v[i]; + packer.pack_fix_double(val1); + msgpack::object_handle oh = + msgpack::unpack(sbuf.data(), sbuf.size()); + double val2 = oh.get().as(); + + if (std::isnan(val1)) + BOOST_CHECK(std::isnan(val2)); + else if (std::isinf(val1)) + BOOST_CHECK(std::isinf(val2)); + else + BOOST_CHECK(fabs(val2 - val1) <= kEPS); + } +} + #endif // !defined(_MSC_VER) || _MSC_VER >=1800 BOOST_AUTO_TEST_CASE(simple_buffer_nil)