From d2651206fe63e643a0e112011387df41ee822b54 Mon Sep 17 00:00:00 2001 From: Milan Kriz Date: Mon, 21 Oct 2024 17:50:01 +0200 Subject: [PATCH] structure data initializer, fix optionals --- extension/freemarker/CompoundField.inc.ftl | 48 ++++++--- extension/freemarker/Structure.cpp.ftl | 34 ++++--- extension/freemarker/Structure.h.ftl | 5 +- runtime/src/zserio/Bitmasks.h | 4 +- runtime/src/zserio/Enums.h | 4 +- runtime/src/zserio/HashCodeUtil.h | 27 +++++ test/language/default_values/CMakeLists.txt | 24 +++++ .../default_values/ClangTidySuppressions.txt | 9 ++ .../cpp/StructureDefaultValuesTest.cpp | 98 +++++++++++++++++++ 9 files changed, 219 insertions(+), 34 deletions(-) create mode 100644 test/language/default_values/CMakeLists.txt create mode 100644 test/language/default_values/ClangTidySuppressions.txt create mode 100644 test/language/default_values/cpp/StructureDefaultValuesTest.cpp diff --git a/extension/freemarker/CompoundField.inc.ftl b/extension/freemarker/CompoundField.inc.ftl index 0a80b29..0b3790f 100644 --- a/extension/freemarker/CompoundField.inc.ftl +++ b/extension/freemarker/CompoundField.inc.ftl @@ -6,6 +6,14 @@ +<#macro field_data_member_type_name field> + <#if field.optional??> + ::zserio::Optional<<@field_data_type_name field/>><#t> + <#else> + <@field_data_type_name field/><#t> + + + <#macro field_data_arg_name field> ${field.name}_<#t> @@ -14,25 +22,24 @@ ${field.name}<#t> -<#macro field_view_type_name field> - <#if field.typeInfo.isSimple> - ${field.typeInfo.typeFullName}<#t> - <#elseif field.typeInfo.isString> - ::std::string_view<#t> - <#elseif field.typeInfo.isExtern> - const ${types.bitBuffer.name}&<#t> - <#elseif field.typeInfo.isBytes> - ::zserio::Span<#t> - <#else> - View<${field.typeInfo.typeFullName}><#t> - - - <#macro field_view_getter_type_name field> + <#local typeName> + <#if field.typeInfo.isSimple> + ${field.typeInfo.typeFullName}<#t> + <#elseif field.typeInfo.isString> + ::std::string_view<#t> + <#elseif field.typeInfo.isExtern> + const ${types.bitBuffer.name}&<#t> + <#elseif field.typeInfo.isBytes> + ::zserio::Span<#t> + <#else> + View<${field.typeInfo.typeFullName}><#t> + + <#if field.optional??> - ::zserio::Optional<<@field_view_type_name field/>><#t> + ::zserio::Optional<${typeName}><#t> <#else> - <@field_view_type_name field/><#t> + ${typeName}<#t> @@ -52,6 +59,15 @@ CHOICE_${field.name}<#t> +<#function has_optional_field fieldList> + <#list fieldList as field> + <#if field.optional??> + <#return true> + + + <#return false> + + <#function needs_allocator fieldList> <#list fieldList as field> <#if field.needsAllocator> diff --git a/extension/freemarker/Structure.cpp.ftl b/extension/freemarker/Structure.cpp.ftl index 23799c7..9d7e732 100644 --- a/extension/freemarker/Structure.cpp.ftl +++ b/extension/freemarker/Structure.cpp.ftl @@ -19,9 +19,13 @@ ${name}::${name}() noexcept : ${name}::${name}(const allocator_type&<#if needs_allocator(fieldList)> allocator) noexcept<#rt> <#list fieldList> <#lt> : - <#items as field> + <#items as field> + <#if field.initializer??> + ${field.name}(${field.initializer}<#if field.needsAllocator>, allocator)<#sep>, + <#else> ${field.name}(<#if field.needsAllocator>allocator)<#sep>, - + + <#else> @@ -169,28 +173,32 @@ bool operator==(const View<${fullName}>&<#if fieldList?has_content || parameterL } -<#macro structure_view_field_less_than lhs rhs indent> +<#macro structure_view_field_less_than field indent> <#local I>${""?left_pad(indent * 4)} -${I}if (${lhs} != ${rhs}) +${I}if (<#if field.optional??>*lhs.${field.getterName}() != <#if field.optional??>*rhs.${field.getterName}()) ${I}{ -${I} return ${lhs} < ${rhs}; + <#if field.typeInfo.isBoolean> + <#-- TODO[Mi-L@]: Remove once operator< for zserio::Bool is implemented in runtime! --> +${I} return static_cast(<#if field.optional??>*lhs.${field.getterName}()) < <#rt> + <#lt>static_cast(<#if field.optional??>*rhs.${field.getterName}()); + <#else> +${I} return <#if field.optional??>*lhs.${field.getterName}() < <#if field.optional??>*rhs.${field.getterName}(); + ${I}} <#macro structure_view_field_less_than_optional field indent> <#local I>${""?left_pad(indent * 4)} <#if field.optional??> -${I}if (${field.getterName}() && other.${field.getterName}()) +${I}if (lhs.${field.getterName}() && rhs.${field.getterName}()) ${I}{ - <@structure_view_field_less_than "*lhs." + field.getterName + "()", "*rhs." + field.getterName + "()", - indent+1/> + <@structure_view_field_less_than field, indent+1/> ${I}} -${I}else if (${field.getterName}() != other.${field.getterName}()) +${I}else if (lhs.${field.getterName}() != rhs.${field.getterName}()) ${I}{ -${I} return !${field.getterName}(); +${I} return !lhs.${field.getterName}(); ${I}} <#else> - <@structure_view_field_less_than "lhs." + field.getterName + "()", "rhs." + field.getterName + "()", - indent/> + <@structure_view_field_less_than field indent/> bool operator<(const View<${fullName}>&<#if fieldList?has_content || parameterList?has_content> lhs, <#rt> @@ -271,7 +279,7 @@ ${I}in.alignTo(${field.alignmentValue}); ${I}in.alignTo(8); <#local compoundArguments><@field_view_parameters field/> -${I}(void)::zserio::detail::read(reader, data.<@field_data_member_name field/><#rt> +${I}(void)::zserio::detail::read(reader, <#if field.optional??>*data.<@field_data_member_name field/><#rt> <#lt><#if compoundArguments?has_content>, ${compoundArguments}); View<${fullName}> read(::zserio::BitStreamReader&<#if fieldList?has_content> reader, <#rt> diff --git a/extension/freemarker/Structure.h.ftl b/extension/freemarker/Structure.h.ftl index 626f6be..dfce39d 100644 --- a/extension/freemarker/Structure.h.ftl +++ b/extension/freemarker/Structure.h.ftl @@ -10,6 +10,9 @@ #include #include +<#if has_optional_field(fieldList)> +#include + <@system_includes headerSystemIncludes/> <@user_includes headerUserIncludes/> <@namespace_begin package.path/> @@ -32,7 +35,7 @@ struct ${name} <#list fieldList as field> - <@field_data_type_name field/> <@field_data_member_name field/>; + <@field_data_member_type_name field/> <@field_data_member_name field/>; }; diff --git a/runtime/src/zserio/Bitmasks.h b/runtime/src/zserio/Bitmasks.h index cedb3bd..51229df 100644 --- a/runtime/src/zserio/Bitmasks.h +++ b/runtime/src/zserio/Bitmasks.h @@ -13,9 +13,9 @@ namespace detail { template -std::enable_if_t, BitSize> bitSizeOf(T value) +std::enable_if_t, BitSize> bitSizeOf(T value, BitSize bitPosition = 0) { - return bitSizeOf(value.getValue()); + return bitSizeOf(value.getValue(), bitPosition); } template diff --git a/runtime/src/zserio/Enums.h b/runtime/src/zserio/Enums.h index b806a94..9905bd7 100644 --- a/runtime/src/zserio/Enums.h +++ b/runtime/src/zserio/Enums.h @@ -99,9 +99,9 @@ namespace detail { template -inline std::enable_if_t, BitSize> bitSizeOf(T value) +inline std::enable_if_t, BitSize> bitSizeOf(T value, BitSize bitPosition = 0) { - return bitSizeOf(enumToValue(value)); + return bitSizeOf(enumToValue(value), bitPosition); } template diff --git a/runtime/src/zserio/HashCodeUtil.h b/runtime/src/zserio/HashCodeUtil.h index ff5727a..2195d4c 100644 --- a/runtime/src/zserio/HashCodeUtil.h +++ b/runtime/src/zserio/HashCodeUtil.h @@ -101,6 +101,33 @@ inline uint32_t calcHashCode(uint32_t seedValue, detail::IntWrapper(value)); } +/** + * Calculates hash code of the given bool wrapper value using the given seed value. + * + * \param seedValue Seed value (current hash code). + * \param value Value for which to calculate the hash code. + * + * \return Calculated hash code. + */ +inline uint32_t calcHashCode(uint32_t seedValue, Bool value) +{ + return calcHashCode(seedValue, static_cast(value)); +} + +/** + * Calculates hash code of the given floating-point wrapper value using the given seed value. + * + * \param seedValue Seed value (current hash code). + * \param value Value for which to calculate the hash code. + * + * \return Calculated hash code. + */ +template +inline uint32_t calcHashCode(uint32_t seedValue, detail::FloatWrapper value) +{ + return calcHashCode(seedValue, static_cast(value)); +} + // TODO[Mi-L@]: support all zserio wrappers /** diff --git a/test/language/default_values/CMakeLists.txt b/test/language/default_values/CMakeLists.txt new file mode 100644 index 0000000..d1c64f8 --- /dev/null +++ b/test/language/default_values/CMakeLists.txt @@ -0,0 +1,24 @@ +add_library(default_values_zs STATIC ${TEST_ZS_ROOT}/default_values.zs) +zserio_generate_cpp( + TARGET default_values_zs + SRC_DIR ${TEST_ZS_ROOT} + GEN_DIR ${CMAKE_CURRENT_BINARY_DIR}/gen + EXTRA_ARGS ${ZSERIO_EXTRA_ARGS} + GENERATED_SOURCES_VAR GENERATED_SOURCES + OUTPUT_VAR ZSERIO_LOG + ERROR_VAR ZSERIO_LOG +) +target_link_libraries(default_values_zs PUBLIC ZserioCpp17Runtime) +if (ZSERIO_LOG) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/zserio_log.txt "${ZSERIO_LOG}") + check_zserio_warnings("${ZSERIO_LOG}" 0) +endif () + +add_custom_test(default_values + DEPENDS + default_values_zs + SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/cpp/StructureDefaultValuesTest.cpp + GENERATED_SOURCES + ${GENERATED_SOURCES} +) diff --git a/test/language/default_values/ClangTidySuppressions.txt b/test/language/default_values/ClangTidySuppressions.txt new file mode 100644 index 0000000..aeac781 --- /dev/null +++ b/test/language/default_values/ClangTidySuppressions.txt @@ -0,0 +1,9 @@ +google-explicit-constructor:gen/default_values/structure_default_values/Permission.h + +#hicpp-signed-bitwise:gen/default_values/structure_default_values/Permission.h + +#readability-make-member-function-const:gen/default_values/structure_default_values/StructureDefaultValues.cpp + +readability-uppercase-literal-suffix:gen/default_values/structure_default_values/StructureDefaultValues.cpp + +readability-simplify-boolean-expr:gen/default_values/structure_default_values/StructureDefaultValues.cpp diff --git a/test/language/default_values/cpp/StructureDefaultValuesTest.cpp b/test/language/default_values/cpp/StructureDefaultValuesTest.cpp new file mode 100644 index 0000000..9271116 --- /dev/null +++ b/test/language/default_values/cpp/StructureDefaultValuesTest.cpp @@ -0,0 +1,98 @@ +#include "default_values/structure_default_values/BasicColor.h" +#include "default_values/structure_default_values/Permission.h" +#include "default_values/structure_default_values/StructureDefaultValues.h" +#include "gtest/gtest.h" +#include "zserio/BitStreamReader.h" +#include "zserio/CppRuntimeException.h" + +namespace default_values +{ +namespace structure_default_values +{ + +TEST(StructureDefaultValuesDataTest, checkDefaultBoolValue) +{ + StructureDefaultValues structureDefaultValues; + ASSERT_EQ(true, structureDefaultValues.boolValue); +} + +TEST(StructureDefaultValuesDataTest, checkDefaultBit4Value) +{ + StructureDefaultValues structureDefaultValues; + ASSERT_EQ(0x0F, structureDefaultValues.bit4Value); +} + +TEST(StructureDefaultValuesDataTest, checkDefaultInt16Value) +{ + StructureDefaultValues structureDefaultValues; + ASSERT_EQ(0x0BEE, structureDefaultValues.int16Value); +} + +TEST(StructureDefaultValuesDataTest, checkDefaultFloat16Value) +{ + StructureDefaultValues structureDefaultValues; + float diff = 1.23F - structureDefaultValues.float16Value; + if (diff < 0.0F) + { + diff = -diff; + } + ASSERT_TRUE(diff <= std::numeric_limits::epsilon()); +} + +TEST(StructureDefaultValuesDataTest, checkDefaultFloat32Value) +{ + StructureDefaultValues structureDefaultValues; + float diff = 1.234F - structureDefaultValues.float32Value; + if (diff < 0.0F) + { + diff = -diff; + } + ASSERT_TRUE(diff <= std::numeric_limits::epsilon()); +} + +TEST(StructureDefaultValuesDataTest, checkDefaultFloat64Value) +{ + StructureDefaultValues structureDefaultValues; + double diff = 1.2345 - structureDefaultValues.float64Value; + if (diff < 0.0) + { + diff = -diff; + } + ASSERT_TRUE(diff <= std::numeric_limits::epsilon()); +} + +TEST(StructureDefaultValuesDataTest, checkDefaultStringValue) +{ + StructureDefaultValues structureDefaultValues; + ASSERT_EQ("string", structureDefaultValues.stringValue); +} + +TEST(StructureDefaultValuesDataTest, checkDefaultEnumValue) +{ + StructureDefaultValues structureDefaultValues; + ASSERT_EQ(BasicColor::BLACK, structureDefaultValues.enumValue); +} + +TEST(StructureDefaultValuesDataTest, checkDefaultBitmaskValue) +{ + StructureDefaultValues structureDefaultValues; + ASSERT_EQ(Permission::Values::READ_WRITE, structureDefaultValues.bitmaskValue); +} + +TEST(StructureDefaultValuesDataTest, operatorEquality) +{ + StructureDefaultValues structureDefaultValues1; + StructureDefaultValues structureDefaultValues2; + ASSERT_EQ(structureDefaultValues1, structureDefaultValues2); +} + +TEST(StructureDefaultValuesDataTest, operatorLessThan) +{ + StructureDefaultValues structureDefaultValues1; + StructureDefaultValues structureDefaultValues2; + ASSERT_FALSE(structureDefaultValues1 < structureDefaultValues2); + ASSERT_FALSE(structureDefaultValues2 < structureDefaultValues1); +} + +} // namespace structure_default_values +} // namespace default_values