encoding: support floating point numbers in TLV-VALUE
refs #4612
Change-Id: I3ca5970b1559c6690826045a0955a26b93663f50
diff --git a/src/encoding/block-helpers.cpp b/src/encoding/block-helpers.cpp
index 93df8e0..49fec54 100644
--- a/src/encoding/block-helpers.cpp
+++ b/src/encoding/block-helpers.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -59,7 +59,7 @@
uint64_t
readNonNegativeInteger(const Block& block)
{
- Buffer::const_iterator begin = block.value_begin();
+ auto begin = block.value_begin();
return tlv::readNonNegativeInteger(block.value_size(), begin, block.value_end());
}
@@ -120,6 +120,53 @@
return std::string(reinterpret_cast<const char*>(block.value()), block.value_size());
}
+// ---- double ----
+
+static_assert(std::numeric_limits<double>::is_iec559, "This code requires IEEE-754 doubles");
+
+template<Tag TAG>
+size_t
+prependDoubleBlock(EncodingImpl<TAG>& encoder, uint32_t type, double value)
+{
+ uint64_t temp = 0;
+ std::memcpy(&temp, &value, 8);
+ boost::endian::native_to_big_inplace(temp);
+ return encoder.prependByteArrayBlock(type, reinterpret_cast<const uint8_t*>(&temp), 8);
+}
+
+template size_t
+prependDoubleBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, double);
+
+template size_t
+prependDoubleBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, double);
+
+Block
+makeDoubleBlock(uint32_t type, double value)
+{
+ EncodingEstimator estimator;
+ size_t totalLength = prependDoubleBlock(estimator, type, value);
+
+ EncodingBuffer encoder(totalLength, 0);
+ prependDoubleBlock(encoder, type, value);
+
+ return encoder.block();
+}
+
+double
+readDouble(const Block& block)
+{
+ if (block.value_size() != 8) {
+ BOOST_THROW_EXCEPTION(tlv::Error("Invalid length for double (must be 8)"));
+ }
+
+ uint64_t temp = 0;
+ std::memcpy(&temp, block.value(), 8);
+ boost::endian::big_to_native_inplace(temp);
+ double d = 0;
+ std::memcpy(&d, &temp, 8);
+ return d;
+}
+
// ---- binary ----
Block
diff --git a/src/encoding/block-helpers.hpp b/src/encoding/block-helpers.hpp
index acde49c..3c2d1e1 100644
--- a/src/encoding/block-helpers.hpp
+++ b/src/encoding/block-helpers.hpp
@@ -29,7 +29,7 @@
namespace ndn {
namespace encoding {
-/** @brief Prepend a TLV element containing a non-negative integer
+/** @brief Prepend a TLV element containing a non-negative integer.
* @param encoder an EncodingBuffer or EncodingEstimator
* @param type TLV-TYPE number
* @param value non-negative integer value
@@ -45,7 +45,7 @@
extern template size_t
prependNonNegativeIntegerBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, uint64_t);
-/** @brief Create a TLV block containing a non-negative integer
+/** @brief Create a TLV block containing a non-negative integer.
* @param type TLV-TYPE number
* @param value non-negative integer value
* @sa prependNonNegativeIntegerBlock, readNonNegativeInteger
@@ -53,7 +53,7 @@
Block
makeNonNegativeIntegerBlock(uint32_t type, uint64_t value);
-/** @brief Read a non-negative integer from a TLV element
+/** @brief Read a non-negative integer from a TLV element.
* @param block the TLV element
* @throw tlv::Error block does not contain a non-negative integer
* @sa prependNonNegativeIntegerBlock, makeNonNegativeIntegerBlock
@@ -61,7 +61,7 @@
uint64_t
readNonNegativeInteger(const Block& block);
-/** @brief Read a non-negative integer from a TLV element and cast to the specified type
+/** @brief Read a non-negative integer from a TLV element and cast to the specified type.
* @tparam R result type, must be an integral type
* @param block the TLV element
* @throw tlv::Error block does not contain a valid non-negative integer or the number cannot be
@@ -79,7 +79,7 @@
return static_cast<R>(value);
}
-/** @brief Read a non-negative integer from a TLV element and cast to the specified type
+/** @brief Read a non-negative integer from a TLV element and cast to the specified type.
* @tparam R result type, must be an enumeration type
* @param block the TLV element
* @throw tlv::Error block does not contain a valid non-negative integer or the number cannot be
@@ -94,7 +94,7 @@
return static_cast<R>(readNonNegativeIntegerAs<std::underlying_type_t<R>>(block));
}
-/** @brief Prepend an empty TLV element
+/** @brief Prepend an empty TLV element.
* @param encoder an EncodingBuffer or EncodingEstimator
* @param type TLV-TYPE number
* @details The TLV element has zero-length TLV-VALUE.
@@ -110,7 +110,7 @@
extern template size_t
prependEmptyBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t);
-/** @brief Create an empty TLV block
+/** @brief Create an empty TLV block.
* @param type TLV-TYPE number
* @return A TLV block with zero-length TLV-VALUE
* @sa prependEmptyBlock
@@ -150,6 +150,38 @@
std::string
readString(const Block& block);
+/** @brief Prepend a TLV element containing an IEEE 754 double-precision floating-point number.
+ * @param encoder an EncodingBuffer or EncodingEstimator
+ * @param type TLV-TYPE number
+ * @param value a floating point number value
+ * @sa makeDoubleBlock, readDouble
+ */
+template<Tag TAG>
+size_t
+prependDoubleBlock(EncodingImpl<TAG>& encoder, uint32_t type, double value);
+
+extern template size_t
+prependDoubleBlock<EstimatorTag>(EncodingImpl<EstimatorTag>&, uint32_t, double);
+
+extern template size_t
+prependDoubleBlock<EncoderTag>(EncodingImpl<EncoderTag>&, uint32_t, double);
+
+/** @brief Create a TLV element containing an IEEE 754 double-precision floating-point number.
+ * @param type TLV-TYPE number
+ * @param value floating point number value
+ * @sa prependDoubleBlock, readDouble
+ */
+Block
+makeDoubleBlock(uint32_t type, double value);
+
+/** @brief Read TLV-VALUE of a TLV element as an IEEE 754 double-precision floating-point number.
+ * @param block the TLV element
+ * @return a floating point number value
+ * @sa prependDoubleBlock, makeDoubleBlock
+ */
+double
+readDouble(const Block& block);
+
/** @brief Create a TLV block copying TLV-VALUE from raw buffer.
* @param type TLV-TYPE number
* @param value raw buffer as TLV-VALUE
@@ -170,7 +202,7 @@
namespace detail {
-/** @brief Create a binary block copying from RandomAccessIterator
+/** @brief Create a binary block copying from RandomAccessIterator.
*/
template<class Iterator>
class BinaryBlockFast
@@ -196,7 +228,7 @@
}
};
-/** @brief Create a binary block copying from generic InputIterator
+/** @brief Create a binary block copying from generic InputIterator.
*/
template<class Iterator>
class BinaryBlockSlow
diff --git a/tests/unit-tests/encoding/block-helpers.t.cpp b/tests/unit-tests/encoding/block-helpers.t.cpp
index 9247e0a..5b9711d 100644
--- a/tests/unit-tests/encoding/block-helpers.t.cpp
+++ b/tests/unit-tests/encoding/block-helpers.t.cpp
@@ -84,6 +84,23 @@
BOOST_CHECK_EQUAL(readString(b), "Hello, world!");
}
+BOOST_AUTO_TEST_CASE(Double)
+{
+ const double f = 0.25;
+ Block b = makeDoubleBlock(100, f);
+ BOOST_CHECK_EQUAL(b, "64083FD0000000000000"_block);
+
+ EncodingEstimator estimator;
+ size_t totalLength = prependDoubleBlock(estimator, 100, f);
+ EncodingBuffer encoder(totalLength, 0);
+ prependDoubleBlock(encoder, 100, f);
+ BOOST_CHECK_EQUAL(encoder.block(), b);
+
+ BOOST_CHECK_EQUAL(readDouble(b), f);
+ BOOST_CHECK_THROW(readDouble("4200"_block), tlv::Error);
+ BOOST_CHECK_THROW(readDouble("64043E800000"_block), tlv::Error);
+}
+
BOOST_AUTO_TEST_CASE(Data)
{
std::string buf1{1, 1, 1, 1};
@@ -99,8 +116,7 @@
BOOST_CHECK_EQUAL(b1, b3);
BOOST_CHECK_EQUAL(b1.type(), 100);
BOOST_CHECK_EQUAL(b1.value_size(), buf1.size());
- BOOST_CHECK_EQUAL_COLLECTIONS(b1.value_begin(), b1.value_end(),
- buf2, buf2 + sizeof(buf2));
+ BOOST_CHECK_EQUAL_COLLECTIONS(b1.value_begin(), b1.value_end(), buf2, buf2 + sizeof(buf2));
}
BOOST_AUTO_TEST_CASE(Nested)