diff --git a/src/leapserial/Archive.cpp b/src/leapserial/Archive.cpp index e9b9744..3a7c9bf 100644 --- a/src/leapserial/Archive.cpp +++ b/src/leapserial/Archive.cpp @@ -39,6 +39,8 @@ const char* leap::ToString(serial_atom atom) { return "f32"; case serial_atom::f64: return "f64"; + case serial_atom::f80: + return "f80"; case serial_atom::reference: return "ref"; case serial_atom::array: diff --git a/src/leapserial/Archive.h b/src/leapserial/Archive.h index 9566c9d..9afd410 100644 --- a/src/leapserial/Archive.h +++ b/src/leapserial/Archive.h @@ -63,6 +63,7 @@ namespace leap { ui64, f32, f64, + f80, reference, array, string, @@ -136,12 +137,14 @@ namespace leap { virtual void WriteInteger(int64_t value) { WriteInteger(value, sizeof(value)); } virtual void WriteInteger(uint64_t value) { WriteInteger((int64_t)value, sizeof(value)); } - virtual void WriteFloat(float value) { WriteByteArray(&value, sizeof(float)); } - virtual void WriteFloat(double value) { WriteByteArray(&value, sizeof(double)); } + virtual void WriteFloat(float value) = 0; + virtual void WriteFloat(double value) = 0; + virtual void WriteFloat(long double value) = 0; virtual uint64_t SizeInteger(int64_t value, uint8_t ncb) const = 0; virtual uint64_t SizeFloat(float value) const = 0; virtual uint64_t SizeFloat(double value) const = 0; + virtual uint64_t SizeFloat(long double value) const = 0; virtual uint64_t SizeBool(bool value) const = 0; virtual uint64_t SizeString(const void* pBuf, uint64_t ncb, uint8_t charSize) const = 0; @@ -280,8 +283,9 @@ namespace leap { /// It is an error for (value & ~(1 << (ncb * 8))) to be nonzero. /// virtual uint64_t ReadInteger(uint8_t ncb) = 0; - virtual void ReadFloat(float& value) { ReadByteArray(&value, sizeof(float)); } - virtual void ReadFloat(double& value) { ReadByteArray(&value, sizeof(double)); } + virtual void ReadFloat(float& value) = 0; + virtual void ReadFloat(double& value) = 0; + virtual void ReadFloat(long double& value) = 0; virtual void ReadDictionary(IDictionaryInserter&& dictionary) = 0; }; diff --git a/src/leapserial/ArchiveFlatbuffer.cpp b/src/leapserial/ArchiveFlatbuffer.cpp index 7d1f4ae..d60b15e 100644 --- a/src/leapserial/ArchiveFlatbuffer.cpp +++ b/src/leapserial/ArchiveFlatbuffer.cpp @@ -13,14 +13,14 @@ using namespace leap; //// https://google.github.io/flatbuffers/md__internals.html /// /// offsets are always written as 32 bit integers -/// +/// /// Structs are all aligned to their size and are written in order. /// /// Tables start with soffset_t (a int32_t) to the vtable for the object, /// followed by all fields as aligned scalars. not all fields need to be present. -/// +/// /// Vtables are constructed of voffset_ts(a uint16_t). -/// +/// /// Strings are vectors of bytes, always null terminated /// vectors are stored as contiguous aligned scalars with a uint32_t element count. /// The standard implementation writes buffers backwards as this reduces the amount @@ -34,7 +34,7 @@ using namespace leap; /// uint16_t size of object in bytes (including vtable offset) /// for N elements in the vtable /// uint16_t offset of Nth field -/// +/// struct not_implemented_exception : public std::runtime_error @@ -133,7 +133,7 @@ void OArchiveFlatbuffer::WriteByteArray(const void* pBuf, uint64_t ncb, bool wri throw not_implemented_exception(); } -void OArchiveFlatbuffer::WriteString(const void* pBuf, uint64_t charCount, uint8_t charSize) { +void OArchiveFlatbuffer::WriteString(const void* pBuf, uint64_t charCount, uint8_t charSize) { if (charSize != 1) throw std::runtime_error("Flatbuffers does not support non ASCII/UTF-8 strings"); @@ -152,13 +152,13 @@ void OArchiveFlatbuffer::WriteString(const void* pBuf, uint64_t charCount, uint8 SaveOffset(m_currentFieldPtr, (uint32_t)m_builder.size()); } -void OArchiveFlatbuffer::WriteBool(bool value) { +void OArchiveFlatbuffer::WriteBool(bool value) { WriteInteger((uint8_t)value); } void OArchiveFlatbuffer::WriteInteger(int64_t value, uint8_t ncb) { Align(ncb); - + uint64_t bits = *reinterpret_cast(&value); for (int i = ncb-1; i >= 0; --i) { const uint8_t lowerBits = (uint8_t)(bits >> (i * 8) & 0x0000000000000FF); @@ -166,15 +166,20 @@ void OArchiveFlatbuffer::WriteInteger(int64_t value, uint8_t ncb) { } } -void OArchiveFlatbuffer::WriteFloat(float value) { +void OArchiveFlatbuffer::WriteFloat(float value) { WriteInteger(*reinterpret_cast(&value)); } -void OArchiveFlatbuffer::WriteFloat(double value) { +void OArchiveFlatbuffer::WriteFloat(double value) { WriteInteger(*reinterpret_cast(&value)); } -void OArchiveFlatbuffer::WriteObjectReference(const field_serializer& serializer, const void* pObj) { +void OArchiveFlatbuffer::WriteFloat(long double value) { + for (size_t i = 0; i < sizeof(value); i++) + WriteInteger(reinterpret_cast(&value)[i]); +} + +void OArchiveFlatbuffer::WriteObjectReference(const field_serializer& serializer, const void* pObj) { throw not_implemented_exception(); } @@ -192,7 +197,7 @@ void OArchiveFlatbuffer::WriteObject(const field_serializer& serializer, const v Finish(); } -void OArchiveFlatbuffer::WriteDescriptor(const descriptor& descriptor, const void* pObj) { +void OArchiveFlatbuffer::WriteDescriptor(const descriptor& descriptor, const void* pObj) { const auto orderedDescriptors = SortFields(descriptor); @@ -221,7 +226,7 @@ void OArchiveFlatbuffer::WriteDescriptor(const descriptor& descriptor, const voi } vTable.offsets.push_back(static_cast((uint32_t)m_builder.size() - tableEnd)); } - + //If there are no identified descriptors, then we are a struct and do not care about vtable stuff. if (descriptor.identified_descriptors.empty()) return; @@ -235,7 +240,7 @@ void OArchiveFlatbuffer::WriteDescriptor(const descriptor& descriptor, const voi vTable.offset = tableStart + vTable.size; auto insertionResult = m_vTables.insert(vTable); - + //Final entry for the table WriteInteger((int32_t)(insertionResult.first->offset - tableStart)); @@ -278,29 +283,32 @@ void OArchiveFlatbuffer::WriteArray(IArrayReader&& ary) { } void OArchiveFlatbuffer::WriteDictionary(IDictionaryReader&& dictionary) -{ +{ throw not_implemented_exception(); } -uint64_t OArchiveFlatbuffer::SizeInteger(int64_t value, uint8_t ncb) const { +uint64_t OArchiveFlatbuffer::SizeInteger(int64_t value, uint8_t ncb) const { return ncb; } -uint64_t OArchiveFlatbuffer::SizeFloat(float value) const { +uint64_t OArchiveFlatbuffer::SizeFloat(float value) const { return sizeof(float); } -uint64_t OArchiveFlatbuffer::SizeFloat(double value) const { +uint64_t OArchiveFlatbuffer::SizeFloat(double value) const { return sizeof(double); } -uint64_t OArchiveFlatbuffer::SizeBool(bool value) const { +uint64_t OArchiveFlatbuffer::SizeFloat(long double value) const { + return sizeof(long double); +} +uint64_t OArchiveFlatbuffer::SizeBool(bool value) const { return sizeof(bool); } -uint64_t OArchiveFlatbuffer::SizeString(const void* pBuf, uint64_t ncb, uint8_t charSize) const { +uint64_t OArchiveFlatbuffer::SizeString(const void* pBuf, uint64_t ncb, uint8_t charSize) const { return sizeof(uint32_t); } -uint64_t OArchiveFlatbuffer::SizeObjectReference(const field_serializer& serializer, const void* pObj) const { +uint64_t OArchiveFlatbuffer::SizeObjectReference(const field_serializer& serializer, const void* pObj) const { return sizeof(uint32_t); } -uint64_t OArchiveFlatbuffer::SizeDescriptor(const descriptor& descriptor, const void* pObj) const { +uint64_t OArchiveFlatbuffer::SizeDescriptor(const descriptor& descriptor, const void* pObj) const { // If stored as a struct, return the size of the struct if (descriptor.identified_descriptors.empty()) { uint64_t size = 0; @@ -308,17 +316,17 @@ uint64_t OArchiveFlatbuffer::SizeDescriptor(const descriptor& descriptor, const size += field_descriptor.serializer.size(*this, pObj); return size; } - + // If stored as a table, return the offset size. return sizeof(uint32_t); } -uint64_t OArchiveFlatbuffer::SizeArray(IArrayReader&& ary) const { +uint64_t OArchiveFlatbuffer::SizeArray(IArrayReader&& ary) const { return sizeof(uint32_t); } uint64_t OArchiveFlatbuffer::SizeDictionary(IDictionaryReader&& dictionary) const -{ +{ throw not_implemented_exception(); } @@ -339,7 +347,7 @@ void IArchiveFlatbuffer::ReadObject(const field_serializer& sz, void* pObj, inte sz.deserialize(*this, pObj, 0); //The root entry is an offset to a table. } -IArchive::ReleasedMemory IArchiveFlatbuffer::ReadObjectReferenceResponsible(IArchive::ReleasedMemory(*pfnAlloc)(), const field_serializer& sz, bool isUnique) { +IArchive::ReleasedMemory IArchiveFlatbuffer::ReadObjectReferenceResponsible(IArchive::ReleasedMemory(*pfnAlloc)(), const field_serializer& sz, bool isUnique) { throw not_implemented_exception(); } @@ -390,7 +398,7 @@ void IArchiveFlatbuffer::ReadByteArray(void* pBuf, uint64_t ncb) { void IArchiveFlatbuffer::ReadString(std::function getBufferFn, uint8_t charSize, uint64_t ncb) { const auto baseOffset = m_offset; const auto stringOffset = baseOffset + GetValue(baseOffset); - + const auto size = GetValue(stringOffset); auto* dstString = getBufferFn(size); @@ -400,9 +408,9 @@ void IArchiveFlatbuffer::ReadString(std::function getBufferFn, m_offset = baseOffset + sizeof(uint32_t); } -bool IArchiveFlatbuffer::ReadBool() { +bool IArchiveFlatbuffer::ReadBool() { const auto offset = m_offset; - m_offset += sizeof(uint8_t); + m_offset += sizeof(uint8_t); return !!GetValue(offset); } @@ -430,7 +438,12 @@ void IArchiveFlatbuffer::ReadFloat(float& value) { void IArchiveFlatbuffer::ReadFloat(double& value) { value = GetValue(m_offset); - m_offset += sizeof(float); + m_offset += sizeof(double); +} + +void IArchiveFlatbuffer::ReadFloat(long double& value) { + value = GetValue(m_offset); + m_offset += sizeof(long double); } void IArchiveFlatbuffer::ReadArray(IArrayAppender&& ary) { diff --git a/src/leapserial/ArchiveFlatbuffer.h b/src/leapserial/ArchiveFlatbuffer.h index 548464c..a1c6ea2 100644 --- a/src/leapserial/ArchiveFlatbuffer.h +++ b/src/leapserial/ArchiveFlatbuffer.h @@ -44,6 +44,7 @@ namespace leap { using OArchive::WriteInteger; void WriteFloat(float value) override; void WriteFloat(double value) override; + void WriteFloat(long double value) override; void WriteObjectReference(const field_serializer& serializer, const void* pObj) override; void WriteObject(const field_serializer& serializer, const void* pObj) override; void WriteDescriptor(const descriptor& descriptor, const void* pObj) override; @@ -55,6 +56,7 @@ namespace leap { uint64_t SizeInteger(int64_t value, uint8_t ncb) const override; uint64_t SizeFloat(float value) const override; uint64_t SizeFloat(double value) const override; + uint64_t SizeFloat(long double value) const override; uint64_t SizeBool(bool value) const override; uint64_t SizeString(const void* pBuf, uint64_t ncb, uint8_t charSize) const override; uint64_t SizeObjectReference(const field_serializer& serializer, const void* pObj) const override; @@ -105,6 +107,7 @@ namespace leap { uint64_t ReadInteger(uint8_t ncb) override; void ReadFloat(float& value) override; void ReadFloat(double& value) override; + void ReadFloat(long double& value) override; void ReadArray(IArrayAppender&& ary) override; void ReadDictionary(IDictionaryInserter&& dictionary) override; diff --git a/src/leapserial/ArchiveJSON.cpp b/src/leapserial/ArchiveJSON.cpp index d368c9a..52473f4 100644 --- a/src/leapserial/ArchiveJSON.cpp +++ b/src/leapserial/ArchiveJSON.cpp @@ -67,11 +67,11 @@ void OArchiveJSON::WriteInteger(uint64_t value) { os << value; } -void OArchiveJSON::WriteFloat(float value) { +void OArchiveJSON::WriteInteger(int64_t value, uint8_t) { os << value; } -void OArchiveJSON::WriteInteger(int64_t value, uint8_t) { +void OArchiveJSON::WriteFloat(float value) { os << value; } @@ -79,6 +79,10 @@ void OArchiveJSON::WriteFloat(double value) { os << value; } +void OArchiveJSON::WriteFloat(long double value) { + os << value; +} + void OArchiveJSON::WriteObjectReference(const field_serializer& serializer, const void* pObj) { throw not_implemented_exception(); } @@ -103,7 +107,7 @@ void OArchiveJSON::WriteDescriptor(const descriptor& descriptor, const void* pOb os << "\"" << field_descriptor.name << "\":"; if (PrettyPrint) os << ' '; - + const void* pChildObj = pBase + field_descriptor.offset; field_descriptor.serializer.serialize(*this, pChildObj); @@ -162,6 +166,9 @@ uint64_t OArchiveJSON::SizeFloat(float value) const { uint64_t OArchiveJSON::SizeFloat(double value) const { throw not_implemented_exception(); } +uint64_t OArchiveJSON::SizeFloat(long double value) const { + throw not_implemented_exception(); +} uint64_t OArchiveJSON::SizeBool(bool value) const { throw not_implemented_exception(); } @@ -194,7 +201,7 @@ void OArchiveJSON::TabOut(void) const { } IArchiveJSON::IArchiveJSON(std::istream& is) { - + } void IArchiveJSON::Skip(uint64_t ncb) { diff --git a/src/leapserial/ArchiveJSON.h b/src/leapserial/ArchiveJSON.h index f0e7d08..ce6a174 100644 --- a/src/leapserial/ArchiveJSON.h +++ b/src/leapserial/ArchiveJSON.h @@ -38,6 +38,7 @@ namespace leap { void WriteInteger(uint64_t value) override; void WriteFloat(float value) override; void WriteFloat(double value) override; + void WriteFloat(long double value) override; void WriteObjectReference(const field_serializer& serializer, const void* pObj) override; void WriteObject(const field_serializer& serializer, const void* pObj) override; void WriteDescriptor(const descriptor& descriptor, const void* pObj) override; @@ -49,6 +50,7 @@ namespace leap { uint64_t SizeInteger(int64_t value, uint8_t ncb) const override; uint64_t SizeFloat(float value) const override; uint64_t SizeFloat(double value) const override; + uint64_t SizeFloat(long double value) const override; uint64_t SizeBool(bool value) const override; uint64_t SizeString(const void* pBuf, uint64_t ncb, uint8_t charSize) const override; uint64_t SizeObjectReference(const field_serializer& serializer, const void* pObj) const override; @@ -60,7 +62,7 @@ namespace leap { // Current tab level, if pretty printing is turned on, otherwise ignored size_t currentTabLevel = 0; std::ostream& os; - + // Prints TabLevel spaces to the output stream void TabOut(void) const; }; diff --git a/src/leapserial/IArchiveImpl.h b/src/leapserial/IArchiveImpl.h index 5a0d710..4a8f595 100644 --- a/src/leapserial/IArchiveImpl.h +++ b/src/leapserial/IArchiveImpl.h @@ -104,8 +104,9 @@ namespace leap { void ReadString(std::function getBufferFn, uint8_t charSize, uint64_t ncb) override; bool ReadBool() override; uint64_t ReadInteger(uint8_t ncb) override; - void ReadFloat(float& value) override { ReadByteArray(&value, sizeof(float)); } - void ReadFloat(double& value) override { ReadByteArray(&value, sizeof(double)); } + void ReadFloat(float& value) override { ReadByteArray(&value, sizeof(value)); } + void ReadFloat(double& value) override { ReadByteArray(&value, sizeof(value)); } + void ReadFloat(long double& value) override { ReadByteArray(&value, sizeof(value)); } void ReadDescriptor(const descriptor& descriptor, void* pObj, uint64_t ncb) override; void ReadArray(IArrayAppender&& ary) override; void ReadDictionary(IDictionaryInserter&& dictionary) override; diff --git a/src/leapserial/IArchiveProtobuf.cpp b/src/leapserial/IArchiveProtobuf.cpp index 38ffded..84f854c 100644 --- a/src/leapserial/IArchiveProtobuf.cpp +++ b/src/leapserial/IArchiveProtobuf.cpp @@ -114,6 +114,20 @@ uint64_t IArchiveProtobuf::ReadInteger(uint8_t) { return leap::FromBase128(buf, ncb); } +void IArchiveProtobuf::ReadFloat(float& value) { + is.Read(&value, sizeof(value)); +} + +void IArchiveProtobuf::ReadFloat(double& value) { + is.Read(&value, sizeof(value)); +} + +void IArchiveProtobuf::ReadFloat(long double& value) { + double temp; + ReadFloat(temp); + value = temp; +} + void IArchiveProtobuf::ReadArray(IArrayAppender&& ary) { // Protobuf array deserialization is funny, it's just a bunch of single entries repeated // over and over again. diff --git a/src/leapserial/IArchiveProtobuf.h b/src/leapserial/IArchiveProtobuf.h index b84fcdd..c98f37c 100644 --- a/src/leapserial/IArchiveProtobuf.h +++ b/src/leapserial/IArchiveProtobuf.h @@ -20,8 +20,9 @@ namespace leap { void ReadString(std::function getBufferFn, uint8_t charSize, uint64_t ncb) override; bool ReadBool(void) override; uint64_t ReadInteger(uint8_t) override; - void ReadFloat(float& value) override { is.Read(&value, sizeof(value)); } - void ReadFloat(double& value) override { is.Read(&value, sizeof(value)); } + void ReadFloat(float& value) override; + void ReadFloat(double& value) override; + void ReadFloat(long double& value) override; void ReadArray(IArrayAppender&& ary) override; void ReadDictionary(IDictionaryInserter&& rdr) override; diff --git a/src/leapserial/OArchiveImpl.h b/src/leapserial/OArchiveImpl.h index 6a477b2..5584d88 100644 --- a/src/leapserial/OArchiveImpl.h +++ b/src/leapserial/OArchiveImpl.h @@ -71,6 +71,9 @@ namespace leap { void WriteString(const void* pbuf, uint64_t charCount, uint8_t charSize) override; void WriteBool(bool value) override; void WriteInteger(int64_t value, uint8_t ncb) override; + void WriteFloat(float value) override { WriteByteArray(&value, sizeof(value)); } + void WriteFloat(double value) override { WriteByteArray(&value, sizeof(value)); } + void WriteFloat(long double value) override { WriteByteArray(&value, sizeof(value)); } void WriteArray(IArrayReader&& ary) override; void WriteDictionary(IDictionaryReader&& dictionary) override; @@ -83,6 +86,7 @@ namespace leap { uint64_t SizeInteger(int64_t value, uint8_t ncb) const override; uint64_t SizeFloat(float value) const override { return sizeof(float); } uint64_t SizeFloat(double value) const override { return sizeof(double); } + uint64_t SizeFloat(long double value) const override { return sizeof(long double); } uint64_t SizeBool(bool) const override { return 1; } }; } diff --git a/src/leapserial/OArchiveProtobuf.cpp b/src/leapserial/OArchiveProtobuf.cpp index 90ae02e..a669056 100644 --- a/src/leapserial/OArchiveProtobuf.cpp +++ b/src/leapserial/OArchiveProtobuf.cpp @@ -45,6 +45,11 @@ void OArchiveProtobuf::WriteFloat(double value) { os.Write(&value, sizeof(value)); } +void OArchiveProtobuf::WriteFloat(long double value) { + // No support in protobuf for long double, we have to go down to 64 bits + WriteFloat((double)value); +} + void OArchiveProtobuf::WriteObjectReference(const field_serializer& serializer, const void* pObj) { } @@ -86,6 +91,7 @@ void OArchiveProtobuf::WriteDescriptor(const descriptor& descriptor, const void* case serial_atom::ui64: case serial_atom::f32: case serial_atom::f64: + case serial_atom::f80: // These types are all context-free, we are responsible for writing the identifier here, and the // type itself will handle things from there. WriteInteger((member_field.identifier << 3) | (size_t)ToWireType(member_field.serializer.type()), 8); @@ -156,7 +162,7 @@ void OArchiveProtobuf::WriteDictionary(IDictionaryReader&& dictionary) { valSize + (valueType == WireType::LenDelimit ? leap::SizeBase128(valSize) : 0), 8 ); - + WriteInteger(keyID, 8); if (keyType == WireType::LenDelimit) WriteInteger(dictionary.key_serializer.size(*this, dictionary.key()), 8); @@ -182,7 +188,7 @@ uint64_t OArchiveProtobuf::SizeObjectReference(const field_serializer& serialize uint64_t OArchiveProtobuf::SizeDescriptor(const descriptor& descriptor, const void* pObj) const { leap::internal::Pusher p(curDescEntry); - + // Context-free. We just write out the identified fields in order. uint64_t retVal = 0; for (const auto& identified_descriptor : descriptor.identified_descriptors) { @@ -200,6 +206,7 @@ uint64_t OArchiveProtobuf::SizeDescriptor(const descriptor& descriptor, const vo case serial_atom::ui64: case serial_atom::f32: case serial_atom::f64: + case serial_atom::f80: case serial_atom::string: case serial_atom::descriptor: case serial_atom::finalized_descriptor: @@ -215,7 +222,7 @@ uint64_t OArchiveProtobuf::SizeDescriptor(const descriptor& descriptor, const vo case serial_atom::ignored: throw std::runtime_error("Invalid serialization atom type returned"); } - + uint64_t ncb = member_field.serializer.size( *this, reinterpret_cast(pObj) + member_field.offset diff --git a/src/leapserial/OArchiveProtobuf.h b/src/leapserial/OArchiveProtobuf.h index 04cc551..b92e1e9 100644 --- a/src/leapserial/OArchiveProtobuf.h +++ b/src/leapserial/OArchiveProtobuf.h @@ -19,6 +19,7 @@ namespace leap { void WriteInteger(int64_t value, uint8_t) override; void WriteFloat(float value) override; void WriteFloat(double value) override; + void WriteFloat(long double value) override; void WriteObjectReference(const field_serializer& serializer, const void* pObj) override; void WriteObject(const field_serializer& serializer, const void* pObj) override; @@ -39,6 +40,7 @@ namespace leap { uint64_t SizeInteger(int64_t value, uint8_t) const override; uint64_t SizeFloat(float value) const override { return 4; } uint64_t SizeFloat(double value) const override { return 8; } + uint64_t SizeFloat(long double value) const override { return 8; } uint64_t SizeBool(bool value) const override { return 1; } uint64_t SizeString(const void* pBuf, uint64_t ncb, uint8_t charSize) const override; uint64_t SizeObjectReference(const field_serializer& serializer, const void* pObj) const override; diff --git a/src/leapserial/ProtobufType.h b/src/leapserial/ProtobufType.h index 962bc53..bf78fc8 100644 --- a/src/leapserial/ProtobufType.h +++ b/src/leapserial/ProtobufType.h @@ -27,6 +27,7 @@ namespace leap { case serial_atom::f32: return serial_type::b32; case serial_atom::f64: + case serial_atom::f80: return serial_type::b64; default: return serial_type::string; diff --git a/src/leapserial/ProtobufUtil.cpp b/src/leapserial/ProtobufUtil.cpp index b834390..adfc220 100644 --- a/src/leapserial/ProtobufUtil.cpp +++ b/src/leapserial/ProtobufUtil.cpp @@ -24,6 +24,7 @@ WireType leap::internal::protobuf::ToWireType(serial_atom atom) { case serial_atom::f32: return WireType::DoubleWord; case serial_atom::f64: + case serial_atom::f80: return WireType::QuadWord; case serial_atom::reference: case serial_atom::array: @@ -61,6 +62,7 @@ const char* leap::internal::protobuf::ToProtobufField(serial_atom atom) { case serial_atom::f32: return "float"; case serial_atom::f64: + case serial_atom::f80: return "double"; case serial_atom::reference: break; diff --git a/src/leapserial/serial_traits.h b/src/leapserial/serial_traits.h index b493aef..e8b199f 100644 --- a/src/leapserial/serial_traits.h +++ b/src/leapserial/serial_traits.h @@ -69,10 +69,17 @@ namespace leap { static const bool is_optional = false; static ::leap::serial_atom type() { - if (sizeof(T) == sizeof(float)) + if (std::is_same::value) return ::leap::serial_atom::f32; - else if (sizeof(T) == sizeof(double)) + if (std::is_same::value) return ::leap::serial_atom::f64; + if (std::is_same::value) { + if(sizeof(long double) == sizeof(double)) + // Special case for certain compilers which treat long double as a synonym for double + return ::leap::serial_atom::f64; + else + return ::leap::serial_atom::f80; + } } // Trivial serialization/deserialization operations diff --git a/src/leapserial/test/SerializationTest.cpp b/src/leapserial/test/SerializationTest.cpp index 7fcb31f..18c5397 100644 --- a/src/leapserial/test/SerializationTest.cpp +++ b/src/leapserial/test/SerializationTest.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -784,3 +785,34 @@ TEST_F(SerializationTest, FixedSizeForwardsCompatCheck) { ASSERT_EQ(b.member1, a.member1); ASSERT_EQ(b.member2, a.member2); } + +namespace { + class HasManyFloats { + public: + float a = 99.0f; + double b = 99.0; + long double c = 99.0; + + static leap::descriptor GetDescriptor(void) { + return{ + &HasManyFloats::a, + &HasManyFloats::b, + &HasManyFloats::c + }; + } + }; +} + +TEST_F(SerializationTest, FloatingTypesTest) { + HasManyFloats hmf; + hmf.a = std::nextafter(10000.0f, 10000.1f); + hmf.b = std::nextafter(20000.0, 20000.1); + hmf.c = std::nextafter(30000.0L, 30000.1L); + + std::stringstream ss; + leap::Serialize(ss, hmf); + auto deserialized = leap::Deserialize(ss); + ASSERT_EQ(hmf.a, deserialized->a) << "Float datatype not properly round-trip serialized"; + ASSERT_EQ(hmf.b, deserialized->b) << "Double datatype not properly round-trip serialized"; + ASSERT_EQ(hmf.c, deserialized->c) << "Long double datatype not properly round-trip serialized"; +}