Add support for float and double values to libcppbor.

Taken from: http://cl/649433692

Change-Id: Ieeb4da07bb051a756729f44c948d63e61118893f
diff --git a/README.md b/README.md
index 6463766..4558779 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
 * Parsing Indefinite length values for major types 2 (byte string) and 3 (text string)
 * Writing Indefinite length values
 * Semantic tagging
-* Floating point
+* Half floating point
 
 LibCppBor requires C++-17.
 
@@ -38,7 +38,10 @@
   variable-length array of pairs of `Item`s.
 * `Simple` corresponds to major type 7.  It's an abstract class since
   items require more specific type.
-* `Bool` is the only currently-implemented subclass of `Simple`.
+* `Bool` is implemented as a subclass of `Simple`.
+* `Null` is implemented as a subclass of `Simple`.
+* `Float` is implemented as a subclass of `Simple`.
+* `Double` is implemented as a subclass of `Simple`.
 
 Note that major type 6, semantic tag, is not yet implemented.
 
diff --git a/include/cppbor/cppbor.h b/include/cppbor/cppbor.h
index 043e833..6ea1296 100644
--- a/include/cppbor/cppbor.h
+++ b/include/cppbor/cppbor.h
@@ -18,7 +18,9 @@
 
 #include <algorithm>
 #include <cassert>
+#include <cstddef>
 #include <cstdint>
+#include <cstring>
 #include <functional>
 #include <iterator>
 #include <memory>
@@ -56,7 +58,9 @@
 
 enum SimpleType {
     BOOLEAN,
-    NULL_T,  // Only two supported, as yet.
+    NULL_T,
+    FLOAT,
+    DOUBLE,   // Only four supported, as yet.
 };
 
 enum SpecialAddlInfoValues : uint8_t {
@@ -66,7 +70,9 @@
     ONE_BYTE_LENGTH = 24,
     TWO_BYTE_LENGTH = 25,
     FOUR_BYTE_LENGTH = 26,
+    FLOAT_V = 26,
     EIGHT_BYTE_LENGTH = 27,
+    DOUBLE_V = 27,
     INDEFINITE_LENGTH = 31,
 };
 
@@ -85,6 +91,8 @@
 class EncodedItem;
 class ViewTstr;
 class ViewBstr;
+class Float;
+class Double;
 
 /**
  * Returns the size of a CBOR header that contains the additional info value addlInfo.
@@ -148,6 +156,10 @@
     const Bool* asBool() const { return const_cast<Item*>(this)->asBool(); }
     virtual Null* asNull() { return nullptr; }
     const Null* asNull() const { return const_cast<Item*>(this)->asNull(); }
+    virtual Float* asFloat() { return nullptr; }
+    const Float* asFloat() const { return const_cast<Item*>(this)->asFloat(); }
+    virtual Double* asDouble() { return nullptr; }
+    const Double* asDouble() const { return const_cast<Item*>(this)->asDouble(); }
 
     virtual Map* asMap() { return nullptr; }
     const Map* asMap() const { return const_cast<Item*>(this)->asMap(); }
@@ -926,6 +938,80 @@
     std::unique_ptr<Item> clone() const override { return std::make_unique<Null>(); }
 };
 
+#ifdef __STDC_IEC_559__
+/**
+ * Float is a concrete type that implements CBOR major type 7, with additional item value for
+ * FLOAT.
+ */
+class Float : public Simple {
+ public:
+  static constexpr SimpleType kSimpleType = FLOAT;
+
+  explicit Float(float v) : mValue(v) {}
+
+  SimpleType simpleType() const override { return kSimpleType; }
+  Float* asFloat() override { return this; }
+
+  float value() const { return mValue; }
+  size_t encodedSize() const override { return 5; }
+
+  using Item::encode;
+  uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
+      uint32_t bits;
+      std::memcpy(&bits, &mValue, sizeof(float));
+      return encodeHeader(bits, pos, end);
+  }
+  void encode(EncodeCallback encodeCallback) const override {
+      uint32_t bits;
+      std::memcpy(&bits, &mValue, sizeof(float));
+      encodeHeader(bits, encodeCallback);
+  }
+
+  std::unique_ptr<Item> clone() const override {
+    return std::make_unique<Float>(mValue);
+  }
+
+ private:
+    float mValue;
+};
+
+/**
+ * Double is a concrete type that implements CBOR major type 7, with additional item value for
+ * DOUBLE.
+ */
+class Double : public Simple {
+ public:
+  static constexpr SimpleType kSimpleType = DOUBLE;
+
+  explicit Double(double v) : mValue(v) {}
+
+  SimpleType simpleType() const override { return kSimpleType; }
+  Double* asDouble() override { return this; }
+
+  double value() const { return mValue; }
+  size_t encodedSize() const override { return 9; }
+
+  using Item::encode;
+  uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
+      uint64_t bits;
+      std::memcpy(&bits, &mValue, sizeof(double));
+      return encodeHeader(bits, pos, end);
+  }
+  void encode(EncodeCallback encodeCallback) const override {
+      uint64_t bits;
+      std::memcpy(&bits, &mValue, sizeof(double));
+      encodeHeader(bits, encodeCallback);
+  }
+
+  std::unique_ptr<Item> clone() const override {
+    return std::make_unique<Double>(mValue);
+  }
+
+ private:
+    double mValue;
+};
+#endif  // __STDC_IEC_559__
+
 /**
  * Returns pretty-printed CBOR for |item|
  *
diff --git a/src/cppbor.cpp b/src/cppbor.cpp
index d916ce4..14fcdde 100644
--- a/src/cppbor.cpp
+++ b/src/cppbor.cpp
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 #include <openssl/sha.h>
 #include <cstdint>
+#include <cstdio>
 
 #include "cppbor_parse.h"
 
@@ -237,17 +238,35 @@
         } break;
 
         case SIMPLE:
-            const Bool* asBool = item->asSimple()->asBool();
-            const Null* asNull = item->asSimple()->asNull();
-            if (asBool != nullptr) {
-                out.append(asBool->value() ? "true" : "false");
-            } else if (asNull != nullptr) {
-                out.append("null");
-            } else {
+            switch (item->asSimple()->simpleType()) {
+                case BOOLEAN:
+                    out.append(item->asSimple()->asBool()->value() ? "true" : "false");
+                    break;
+                case NULL_T:
+                    out.append("null");
+                    break;
+#ifdef __STDC_IEC_559__
+                case FLOAT:
+                    snprintf(buf, sizeof(buf), "%f", item->asSimple()->asFloat()->value());
+                    out.append(buf);
+                    break;
+                case DOUBLE:
+                    snprintf(buf, sizeof(buf), "%f", item->asSimple()->asDouble()->value());
+                    out.append(buf);
+                    break;
+#else
+                case FLOAT:
+                case DOUBLE:
 #ifndef __TRUSTY__
-                LOG(ERROR) << "Only boolean/null is implemented for SIMPLE";
+                    LOG(ERROR) << "float/double not supported for this platform.";
 #endif  // __TRUSTY__
-                return false;
+                    return false;
+                #endif  // __STDC_IEC_559__
+                default:
+#ifndef __TRUSTY__
+                    LOG(ERROR) << "Only boolean/null/float/double is implemented for SIMPLE";
+#endif  // __TRUSTY__
+                    return false;
             }
             break;
     }
@@ -372,6 +391,12 @@
             return *asBool() == *(other.asBool());
         case NULL_T:
             return true;
+#ifdef __STDC_IEC_559__
+        case FLOAT:
+            return *asFloat() == *(other.asFloat());
+        case DOUBLE:
+            return *asDouble() == *(other.asDouble());
+#endif  // __STDC_IEC_559__
         default:
             CHECK(false);  // Impossible to get here.
             return false;
diff --git a/src/cppbor_parse.cpp b/src/cppbor_parse.cpp
index 6b01df3..6c8a3cd 100644
--- a/src/cppbor_parse.cpp
+++ b/src/cppbor_parse.cpp
@@ -17,6 +17,8 @@
 #include "cppbor_parse.h"
 
 #include <algorithm>
+#include <cstdint>
+#include <cstring>
 #include <memory>
 #include <optional>
 #include <sstream>
@@ -102,6 +104,28 @@
             parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
 }
 
+#ifdef __STDC_IEC_559__
+std::tuple<const uint8_t*, ParseClient*> handleFloat(uint32_t value, const uint8_t* hdrBegin,
+                                                    const uint8_t* hdrEnd,
+                                                    ParseClient* parseClient) {
+    float f;
+    std::memcpy(&f, &value, sizeof(float));
+    std::unique_ptr<Item> item = std::make_unique<Float>(f);
+    return {hdrEnd,
+            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
+}
+
+std::tuple<const uint8_t*, ParseClient*> handleDouble(uint64_t value, const uint8_t* hdrBegin,
+                                                    const uint8_t* hdrEnd,
+                                                    ParseClient* parseClient) {
+    double d;
+    std::memcpy(&d, &value, sizeof(double));
+    std::unique_ptr<Item> item = std::make_unique<Double>(d);
+    return {hdrEnd,
+            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
+}
+#endif  // __STDC_IEC_559__
+
 template <typename T>
 std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
                                                       const uint8_t* valueBegin, const uint8_t* end,
@@ -354,14 +378,25 @@
                                   end, "semantic", emitViews, parseClient, depth);
 
         case SIMPLE:
-            switch (*addlData) {
+            switch (tagInt) {
                 case TRUE:
                 case FALSE:
                     return handleBool(*addlData, begin, pos, parseClient);
+#ifdef __STDC_IEC_559__
+                case FLOAT_V:
+                    return handleFloat(*addlData, begin, pos, parseClient);
+                case DOUBLE_V:
+                    return handleDouble(*addlData, begin, pos, parseClient);
+#else
+                case FLOAT_V:
+                case DOUBLE_V:
+                    parseClient->error(begin, "Unsupported floating-point value for platform.");
+                    return {begin, nullptr};
+#endif  // __STDC_IEC_559__
                 case NULL_V:
                     return handleNull(begin, pos, parseClient);
                 default:
-                    parseClient->error(begin, "Unsupported floating-point or simple value.");
+                    parseClient->error(begin, "Unsupported half-floating-point or simple value.");
                     return {begin, nullptr};
             }
     }
diff --git a/tests/cppbor_test.cpp b/tests/cppbor_test.cpp
index b977581..b6f7b05 100644
--- a/tests/cppbor_test.cpp
+++ b/tests/cppbor_test.cpp
@@ -1946,18 +1946,161 @@
     auto [item, pos, message] = parse(unassignedSimpleValue);
     EXPECT_THAT(item, IsNull());
     EXPECT_EQ(pos, unassignedSimpleValue.data());
-    EXPECT_EQ("Unsupported floating-point or simple value.", message);
+    EXPECT_EQ("Unsupported half-floating-point or simple value.", message);
 }
 
+#ifdef __STDC_IEC_559__
 TEST(FullParserTest, FloatingPointValue) {
     vector<uint8_t> floatingPointValue = {0xFA, 0x12, 0x75, 0x34, 0x37};
+    float f_val = 7.737272847557572e-28;
 
     auto [item, pos, message] = parse(floatingPointValue);
-    EXPECT_THAT(item, IsNull());
-    EXPECT_EQ(pos, floatingPointValue.data());
-    EXPECT_EQ("Unsupported floating-point or simple value.", message);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asFloat()->value(), f_val);
+
+    Float f(f_val);
+    EXPECT_EQ(f.encode(), floatingPointValue);
 }
 
+TEST(FullParserTest, PositiveInfinityFloatingPointValue) {
+    vector<uint8_t> floatingPointValue = {0xFA, 0x7F, 0x80, 0x00, 0x00};
+    float f_val = std::numeric_limits<float>::infinity();
+
+    auto [item, pos, message] = parse(floatingPointValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asFloat()->value(), f_val);
+
+    Float f(f_val);
+    EXPECT_EQ(f.encode(), floatingPointValue);
+}
+
+TEST(FullParserTest, NegativeInfinityFloatingPointValue) {
+    vector<uint8_t> floatingPointValue = {0xFA, 0xFF, 0x80, 0x00, 0x00};
+    float f_val = -std::numeric_limits<float>::infinity();
+
+    auto [item, pos, message] = parse(floatingPointValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asFloat()->value(), f_val);
+
+    Float f(f_val);
+    EXPECT_EQ(f.encode(), floatingPointValue);
+}
+
+TEST(FullParserTest, QuietNaNFloatingPointValue) {
+    vector<uint8_t> floatingPointValue = {0xFA, 0x7F, 0xC0, 0x00, 0x00};
+
+    auto [item, pos, message] = parse(floatingPointValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_TRUE(std::isnan(item->asSimple()->asFloat()->value()));
+
+    float f_val = std::numeric_limits<float>::quiet_NaN();
+    Float f(f_val);
+    EXPECT_EQ(f.encode(), floatingPointValue);
+}
+
+TEST(FullParserTest, MaxFloatingPointValue) {
+    vector<uint8_t> floatingPointValue = {0xFA, 0x7F, 0x7F, 0xFF, 0xFF};
+    float f_val = std::numeric_limits<float>::max();
+
+    auto [item, pos, message] = parse(floatingPointValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asFloat()->value(), f_val);
+
+    Float f(f_val);
+    EXPECT_EQ(f.encode(), floatingPointValue);
+}
+
+TEST(FullParserTest, MinFloatingPointValue) {
+    vector<uint8_t> floatingPointValue = {0xFA, 0x00, 0x80, 0x00, 0x00};
+    float f_val = std::numeric_limits<float>::min();
+
+    auto [item, pos, message] = parse(floatingPointValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asFloat()->value(), f_val);
+
+    Float f(f_val);
+    EXPECT_EQ(f.encode(), floatingPointValue);
+}
+
+TEST(FullParserTest, DoubleValue) {
+    vector<uint8_t> doubleValue =
+            {0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A};
+    double d_val = 3.1415926000000001;
+
+    auto [item, pos, message] = parse(doubleValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asDouble()->value(), d_val);
+
+    Double d(d_val);
+    EXPECT_EQ(d.encode(), doubleValue);
+}
+
+TEST(FullParserTest, PositiveInfinityDoubleValue) {
+    vector<uint8_t> doubleValue =
+            {0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    double d_val = std::numeric_limits<double>::infinity();
+
+    auto [item, pos, message] = parse(doubleValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asDouble()->value(), d_val);
+
+    Double d(d_val);
+    EXPECT_EQ(d.encode(), doubleValue);
+}
+
+TEST(FullParserTest, NegativeInfinityDoubleValue) {
+    vector<uint8_t> doubleValue =
+            {0xFB, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    double d_val = -std::numeric_limits<double>::infinity();
+
+    auto [item, pos, message] = parse(doubleValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asDouble()->value(), d_val);
+
+    Double d(d_val);
+    EXPECT_EQ(d.encode(), doubleValue);
+}
+
+TEST(FullParserTest, QuietNaNDoubleValue) {
+    vector<uint8_t> doubleValue =
+            {0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+    auto [item, pos, message] = parse(doubleValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_TRUE(std::isnan(item->asSimple()->asDouble()->value()));
+
+    double d_val = std::numeric_limits<double>::quiet_NaN();
+    Double d(d_val);
+    EXPECT_EQ(d.encode(), doubleValue);
+}
+
+TEST(FullParserTest, MaxDoubleValue) {
+    vector<uint8_t> doubleValue =
+            {0xFB, 0x7F, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+    double d_val = std::numeric_limits<double>::max();
+
+    auto [item, pos, message] = parse(doubleValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asDouble()->value(), d_val);
+
+    Double d(d_val);
+    EXPECT_EQ(d.encode(), doubleValue);
+}
+
+TEST(FullParserTest, MinDoubleValue) {
+    vector<uint8_t> doubleValue =
+            {0xFB, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    double d_val = std::numeric_limits<double>::min();
+
+    auto [item, pos, message] = parse(doubleValue);
+    EXPECT_THAT(item, NotNull());
+    EXPECT_EQ(item->asSimple()->asDouble()->value(), d_val);
+
+    Double d(d_val);
+    EXPECT_EQ(d.encode(), doubleValue);
+}
+#endif  // __STDC_IEC_559__
+
 TEST(MapGetValueByKeyTest, Map) {
     Array compoundItem(1, 2, 3, 4, 5, Map(4, 5, "a", "b"));
     auto clone = compoundItem.clone();