fprime/Fw/Types/PolyType.cpp
Vince Woo 48e4720419
Created new SerialBufferBase as a parent of SerializeBufferBase (now renamed LinearBufferBase). (#4288)
* Created new SerialBufferBase as a parent of SerializeBufferBase. Renaming interface functions to be less confusing.

* Deprecating copyRawOffset. No direct use-cases in F' core.

* Make SerialBufferBase a true pure virtual interface.

* Changing Serializable to work with SerialBufferBase parent interface.

* Changing copyRaw and copyRawOffset to work with SerialBufferBase

* Updating documentation for SerialBufferBase usage

* Adding some documentation. Adding missing ASSERT in copyRaw. Fixing some bugs that new ASSERT uncovered.

* Renaming SerializeBufferBase to LinearBufferBase. Add a using declaration to maintain backwards compatability. Properly mark LinearBufferBase functions as override.

* Filling in the rest of the docstrings for the classes in Serializable

* Removing redundant virtual keyword on override function

* Applying clang formatting

* Incorporating PR comments

* Fix compile issues

* Bump version to alpha

* Format

* v

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-11-06 16:23:20 -08:00

655 lines
16 KiB
C++

#include <Fw/Types/Assert.hpp>
#include <Fw/Types/ExternalString.hpp>
#include <Fw/Types/PolyType.hpp>
namespace Fw {
// U8 methods
PolyType::PolyType() {
this->m_dataType = TYPE_NOTYPE;
}
PolyType::PolyType(U8 val) {
this->m_dataType = TYPE_U8;
this->m_val.u8Val = val;
}
PolyType::operator U8() {
FW_ASSERT(TYPE_U8 == this->m_dataType);
return this->m_val.u8Val;
}
void PolyType::get(U8& val) {
FW_ASSERT(TYPE_U8 == this->m_dataType);
val = this->m_val.u8Val;
}
bool PolyType::isU8() {
return (TYPE_U8 == this->m_dataType);
}
PolyType& PolyType::operator=(U8 other) {
this->m_dataType = TYPE_U8;
this->m_val.u8Val = other;
return *this;
}
// I8 methods
PolyType::PolyType(I8 val) {
this->m_dataType = TYPE_I8;
this->m_val.i8Val = val;
}
PolyType::operator I8() {
FW_ASSERT(TYPE_I8 == this->m_dataType);
return this->m_val.i8Val;
}
void PolyType::get(I8& val) {
FW_ASSERT(TYPE_I8 == this->m_dataType);
val = this->m_val.i8Val;
}
bool PolyType::isI8() {
return (TYPE_I8 == this->m_dataType);
}
PolyType& PolyType::operator=(I8 other) {
this->m_dataType = TYPE_I8;
this->m_val.i8Val = other;
return *this;
}
#if FW_HAS_16_BIT
// U16 methods
PolyType::PolyType(U16 val) {
this->m_dataType = TYPE_U16;
this->m_val.u16Val = val;
}
PolyType::operator U16() {
FW_ASSERT(TYPE_U16 == this->m_dataType);
return this->m_val.u16Val;
}
void PolyType::get(U16& val) {
FW_ASSERT(TYPE_U16 == this->m_dataType);
val = this->m_val.u16Val;
}
bool PolyType::isU16() {
return (TYPE_U16 == this->m_dataType);
}
PolyType& PolyType::operator=(U16 other) {
this->m_dataType = TYPE_U16;
this->m_val.u16Val = other;
return *this;
}
// I16 methods
PolyType::PolyType(I16 val) {
this->m_dataType = TYPE_I16;
this->m_val.i16Val = val;
}
PolyType::operator I16() {
FW_ASSERT(TYPE_I16 == this->m_dataType);
return this->m_val.i16Val;
}
void PolyType::get(I16& val) {
FW_ASSERT(TYPE_I16 == this->m_dataType);
val = this->m_val.i16Val;
}
bool PolyType::isI16() {
return (TYPE_I16 == this->m_dataType);
}
PolyType& PolyType::operator=(I16 other) {
this->m_dataType = TYPE_I16;
this->m_val.i16Val = other;
return *this;
}
#endif
#if FW_HAS_32_BIT
// U32 methods
PolyType::PolyType(U32 val) {
this->m_dataType = TYPE_U32;
this->m_val.u32Val = val;
}
PolyType::operator U32() {
FW_ASSERT(TYPE_U32 == this->m_dataType);
return this->m_val.u32Val;
}
void PolyType::get(U32& val) {
FW_ASSERT(TYPE_U32 == this->m_dataType);
val = this->m_val.u32Val;
}
bool PolyType::isU32() {
return (TYPE_U32 == this->m_dataType);
}
PolyType& PolyType::operator=(U32 other) {
this->m_dataType = TYPE_U32;
this->m_val.u32Val = other;
return *this;
}
// I32 methods
PolyType::PolyType(I32 val) {
this->m_dataType = TYPE_I32;
this->m_val.i32Val = val;
}
PolyType::operator I32() {
FW_ASSERT(TYPE_I32 == this->m_dataType);
return this->m_val.i32Val;
}
void PolyType::get(I32& val) {
FW_ASSERT(TYPE_I32 == this->m_dataType);
val = this->m_val.i32Val;
}
bool PolyType::isI32() {
return (TYPE_I32 == this->m_dataType);
}
PolyType& PolyType::operator=(I32 other) {
this->m_dataType = TYPE_I32;
this->m_val.i32Val = other;
return *this;
}
#endif
#if FW_HAS_64_BIT
// U64 methods
PolyType::PolyType(U64 val) {
this->m_dataType = TYPE_U64;
this->m_val.u64Val = val;
}
PolyType::operator U64() {
FW_ASSERT(TYPE_U64 == this->m_dataType);
return this->m_val.u64Val;
}
void PolyType::get(U64& val) {
FW_ASSERT(TYPE_U64 == this->m_dataType);
val = this->m_val.u64Val;
}
bool PolyType::isU64() {
return (TYPE_U64 == this->m_dataType);
}
PolyType& PolyType::operator=(U64 other) {
this->m_dataType = TYPE_U64;
this->m_val.u64Val = other;
return *this;
}
// I64 methods
PolyType::PolyType(I64 val) {
this->m_dataType = TYPE_I64;
this->m_val.i64Val = val;
}
PolyType::operator I64() {
FW_ASSERT(TYPE_I64 == this->m_dataType);
return this->m_val.i64Val;
}
void PolyType::get(I64& val) {
FW_ASSERT(TYPE_I64 == this->m_dataType);
val = this->m_val.i64Val;
}
bool PolyType::isI64() {
return (TYPE_I64 == this->m_dataType);
}
PolyType& PolyType::operator=(I64 other) {
this->m_dataType = TYPE_I64;
this->m_val.i64Val = other;
return *this;
}
#endif
PolyType::PolyType(F64 val) {
this->m_dataType = TYPE_F64;
this->m_val.f64Val = val;
}
PolyType::operator F64() {
FW_ASSERT(TYPE_F64 == this->m_dataType);
return this->m_val.f64Val;
}
void PolyType::get(F64& val) {
FW_ASSERT(TYPE_F64 == this->m_dataType);
val = this->m_val.f64Val;
}
bool PolyType::isF64() {
return (TYPE_F64 == this->m_dataType);
}
PolyType& PolyType::operator=(F64 other) {
this->m_dataType = TYPE_F64;
this->m_val.f64Val = other;
return *this;
}
PolyType::PolyType(F32 val) {
this->m_dataType = TYPE_F32;
this->m_val.f32Val = val;
}
PolyType::operator F32() {
FW_ASSERT(TYPE_F32 == this->m_dataType);
return this->m_val.f32Val;
}
void PolyType::get(F32& val) {
FW_ASSERT(TYPE_F32 == this->m_dataType);
val = this->m_val.f32Val;
}
bool PolyType::isF32() {
return (TYPE_F32 == this->m_dataType);
}
PolyType& PolyType::operator=(F32 other) {
this->m_dataType = TYPE_F32;
this->m_val.f32Val = other;
return *this;
}
PolyType::PolyType(bool val) {
this->m_dataType = TYPE_BOOL;
this->m_val.boolVal = val;
}
PolyType::operator bool() {
FW_ASSERT(TYPE_BOOL == this->m_dataType);
return this->m_val.boolVal;
}
void PolyType::get(bool& val) {
FW_ASSERT(TYPE_BOOL == this->m_dataType);
val = this->m_val.boolVal;
}
bool PolyType::isBool() {
return (TYPE_BOOL == this->m_dataType);
}
PolyType& PolyType::operator=(bool other) {
this->m_dataType = TYPE_BOOL;
this->m_val.boolVal = other;
return *this;
}
PolyType::PolyType(void* val) {
this->m_dataType = TYPE_PTR;
this->m_val.ptrVal = val;
}
PolyType::operator void*() {
FW_ASSERT(TYPE_PTR == this->m_dataType);
return this->m_val.ptrVal;
}
void PolyType::get(void*& val) {
FW_ASSERT(TYPE_PTR == this->m_dataType);
val = this->m_val.ptrVal;
}
bool PolyType::isPtr() {
return (TYPE_PTR == this->m_dataType);
}
PolyType& PolyType::operator=(void* other) {
this->m_dataType = TYPE_PTR;
this->m_val.ptrVal = other;
return *this;
}
PolyType::PolyType(const PolyType& original) : Fw::Serializable() {
this->m_dataType = original.m_dataType;
this->m_val = original.m_val;
}
PolyType::~PolyType() {}
PolyType& PolyType::operator=(const PolyType& src) {
this->m_dataType = src.m_dataType;
this->m_val = src.m_val;
return *this;
}
bool PolyType::operator!=(const PolyType& other) const {
return !operator==(other);
}
bool PolyType::operator==(const PolyType& other) const {
// if type doesn't match, not equal
if (this->m_dataType != other.m_dataType) {
return false;
} else {
// check based on type
bool valIsEqual = false;
switch (this->m_dataType) {
case TYPE_U8:
valIsEqual = (this->m_val.u8Val == other.m_val.u8Val);
break;
case TYPE_I8:
valIsEqual = (this->m_val.i8Val == other.m_val.i8Val);
break;
#if FW_HAS_16_BIT
case TYPE_U16:
valIsEqual = (this->m_val.u16Val == other.m_val.u16Val);
break;
case TYPE_I16:
valIsEqual = (this->m_val.i16Val == other.m_val.i16Val);
break;
#endif
#if FW_HAS_32_BIT
case TYPE_U32:
valIsEqual = (this->m_val.u32Val == other.m_val.u32Val);
break;
case TYPE_I32:
valIsEqual = (this->m_val.i32Val == other.m_val.i32Val);
break;
#endif
#if FW_HAS_64_BIT
case TYPE_U64:
valIsEqual = (this->m_val.u64Val == other.m_val.u64Val);
break;
case TYPE_I64:
valIsEqual = (this->m_val.i64Val == other.m_val.i64Val);
break;
#endif
case TYPE_BOOL:
valIsEqual = (this->m_val.boolVal == other.m_val.boolVal);
break;
case TYPE_PTR:
valIsEqual = (this->m_val.ptrVal == other.m_val.ptrVal);
break;
case TYPE_F64: // fall through, shouldn't test floating point
case TYPE_F32: // fall through, shouldn't test floating point
case TYPE_NOTYPE:
valIsEqual = false;
break;
default:
FW_ASSERT(0, static_cast<FwAssertArgType>(this->m_dataType));
return false; // for compiler
}
return valIsEqual;
}
}
bool PolyType::operator<(const PolyType& other) const {
// if type doesn't match, not equal
if (this->m_dataType != other.m_dataType) {
return false;
} else {
// check based on type
bool result = false;
switch (this->m_dataType) {
case TYPE_U8:
result = (this->m_val.u8Val < other.m_val.u8Val);
break;
case TYPE_I8:
result = (this->m_val.i8Val < other.m_val.i8Val);
break;
#if FW_HAS_16_BIT
case TYPE_U16:
result = (this->m_val.u16Val < other.m_val.u16Val);
break;
case TYPE_I16:
result = (this->m_val.i16Val < other.m_val.i16Val);
break;
#endif
#if FW_HAS_32_BIT
case TYPE_U32:
result = (this->m_val.u32Val < other.m_val.u32Val);
break;
case TYPE_I32:
result = (this->m_val.i32Val < other.m_val.i32Val);
break;
#endif
#if FW_HAS_64_BIT
case TYPE_U64:
result = (this->m_val.u64Val < other.m_val.u64Val);
break;
case TYPE_I64:
result = (this->m_val.i64Val < other.m_val.i64Val);
break;
#endif
case TYPE_F64:
result = (this->m_val.f64Val < other.m_val.f64Val);
break;
case TYPE_F32:
result = (this->m_val.f32Val < other.m_val.f32Val);
break;
case TYPE_PTR:
result = (this->m_val.ptrVal < other.m_val.ptrVal);
break;
case TYPE_BOOL: // fall through, shouldn't test bool
case TYPE_NOTYPE:
result = false;
break;
default:
FW_ASSERT(0, static_cast<FwAssertArgType>(this->m_dataType));
return false; // for compiler
}
return result;
}
}
bool PolyType::operator>(const PolyType& other) const {
return other.operator<(*this);
}
bool PolyType::operator>=(const PolyType& other) const {
return (this->operator>(other)) || (this->operator==(other));
}
bool PolyType::operator<=(const PolyType& other) const {
return (this->operator<(other)) || (this->operator==(other));
}
SerializeStatus PolyType::serializeTo(SerialBufferBase& buffer, Fw::Endianness mode) const {
// store type
SerializeStatus stat = buffer.serializeFrom(static_cast<FwEnumStoreType>(this->m_dataType), mode);
if (stat != FW_SERIALIZE_OK) {
return stat;
}
// switch on type
switch (this->m_dataType) {
case TYPE_U8:
stat = buffer.serializeFrom(this->m_val.u8Val, mode);
break;
case TYPE_I8:
stat = buffer.serializeFrom(this->m_val.i8Val, mode);
break;
#if FW_HAS_16_BIT
case TYPE_U16:
stat = buffer.serializeFrom(this->m_val.u16Val, mode);
break;
case TYPE_I16:
stat = buffer.serializeFrom(this->m_val.i16Val, mode);
break;
#endif
#if FW_HAS_32_BIT
case TYPE_U32:
stat = buffer.serializeFrom(this->m_val.u32Val, mode);
break;
case TYPE_I32:
stat = buffer.serializeFrom(this->m_val.i32Val, mode);
break;
#endif
#if FW_HAS_64_BIT
case TYPE_U64:
stat = buffer.serializeFrom(this->m_val.u64Val, mode);
break;
case TYPE_I64:
stat = buffer.serializeFrom(this->m_val.i64Val, mode);
break;
#endif
case TYPE_F64:
stat = buffer.serializeFrom(this->m_val.f64Val, mode);
break;
case TYPE_F32:
stat = buffer.serializeFrom(this->m_val.f32Val, mode);
break;
case TYPE_BOOL:
stat = buffer.serializeFrom(this->m_val.boolVal, mode);
break;
case TYPE_PTR:
stat = buffer.serializeFrom(this->m_val.ptrVal, mode);
break;
default:
stat = FW_SERIALIZE_FORMAT_ERROR;
break;
}
return stat;
}
SerializeStatus PolyType::deserializeFrom(SerialBufferBase& buffer, Fw::Endianness mode) {
// get type
FwEnumStoreType des;
SerializeStatus stat = buffer.deserializeTo(des, mode);
if (stat != FW_SERIALIZE_OK) {
return stat;
} else {
this->m_dataType = static_cast<Type>(des);
// switch on type
switch (this->m_dataType) {
case TYPE_U8:
return buffer.deserializeTo(this->m_val.u8Val, mode);
case TYPE_I8:
return buffer.deserializeTo(this->m_val.i8Val, mode);
#if FW_HAS_16_BIT
case TYPE_U16:
return buffer.deserializeTo(this->m_val.u16Val, mode);
case TYPE_I16:
return buffer.deserializeTo(this->m_val.i16Val, mode);
#endif
#if FW_HAS_32_BIT
case TYPE_U32:
return buffer.deserializeTo(this->m_val.u32Val, mode);
case TYPE_I32:
return buffer.deserializeTo(this->m_val.i32Val, mode);
#endif
#if FW_HAS_64_BIT
case TYPE_U64:
return buffer.deserializeTo(this->m_val.u64Val, mode);
case TYPE_I64:
return buffer.deserializeTo(this->m_val.i64Val, mode);
#endif
case TYPE_F64:
return buffer.deserializeTo(this->m_val.f64Val, mode);
case TYPE_F32:
return buffer.deserializeTo(this->m_val.f32Val, mode);
case TYPE_BOOL:
return buffer.deserializeTo(this->m_val.boolVal, mode);
case TYPE_PTR:
return buffer.deserializeTo(this->m_val.ptrVal, mode);
default:
return FW_DESERIALIZE_FORMAT_ERROR;
}
}
}
#if FW_SERIALIZABLE_TO_STRING || BUILD_UT
void PolyType::toString(StringBase& dest) const {
this->toString(dest, false);
}
void PolyType::toString(StringBase& dest, bool append) const {
char format[21]; // U64 max fits into 20 decimal digits + 1 null terminator
Fw::ExternalString external(format, sizeof format);
switch (this->m_dataType) {
case TYPE_U8:
(void)external.format("%" PRIu8 " ", this->m_val.u8Val);
break;
case TYPE_I8:
(void)external.format("%" PRId8 " ", this->m_val.i8Val);
break;
#if FW_HAS_16_BIT
case TYPE_U16:
(void)external.format("%" PRIu16 " ", this->m_val.u16Val);
break;
case TYPE_I16:
(void)external.format("%" PRId16 " ", this->m_val.i16Val);
break;
#endif
#if FW_HAS_32_BIT
case TYPE_U32:
(void)external.format("%" PRIu32 " ", this->m_val.u32Val);
break;
case TYPE_I32:
(void)external.format("%" PRId32 " ", this->m_val.i32Val);
break;
#endif
#if FW_HAS_64_BIT
case TYPE_U64:
(void)external.format("%" PRIu64 " ", this->m_val.u64Val);
break;
case TYPE_I64:
(void)external.format("%" PRId64 " ", this->m_val.i64Val);
break;
#endif
case TYPE_F64:
(void)external.format("%g ", this->m_val.f64Val);
break;
case TYPE_F32:
(void)external.format("%g ", static_cast<F64>(this->m_val.f32Val));
break;
case TYPE_BOOL:
(void)external.format("%s ", this->m_val.boolVal ? "T" : "F");
break;
case TYPE_PTR:
(void)external.format("%p ", this->m_val.ptrVal);
break;
default:
(void)external.format("%s ", "NT");
break;
}
if (append) {
dest += external;
} else {
dest = external;
}
}
#endif
} // namespace Fw