diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 1ee1638748e..d6e796b7682 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -289,6 +289,8 @@ jobs: -DBUILD_SHARED_LIBS=TRUE^ -DOPENDDS_ACE_TAO_SRC=${{ github.workspace }}\OpenDDS\build\ACE_TAO^ -DOPENDDS_MPC=${{ github.workspace }}\MPC^ + -DOPENDDS_XERCES3=${{ env.VCPKG_INSTALLED_DIR }}/x64-windows^ + -DOPENDDS_OPENSSL=${{ env.VCPKG_INSTALLED_DIR }}/x64-windows^ -DOPENDDS_BUILD_TESTS=TRUE^ -DOPENDDS_CMAKE_VERBOSE=all - uses: ammaraskar/msvc-problem-matcher@0.3.0 @@ -308,6 +310,15 @@ jobs: runs-on: windows-2022 steps: + - name: setup for run-vcpkg + shell: bash + run: | + echo '{ "name": "opendds", "version-string": "github-actions", "dependencies": [ "openssl", "xerces-c" ] }' > vcpkg.json + - name: install openssl & xerces-c + uses: lukka/run-vcpkg@v11 + with: + vcpkgGitCommitId: '${{ env.VCPKG_GIT_COMMIT }}' + runVcpkgInstall: true - name: Checkout OpenDDS uses: actions/checkout@v4 with: @@ -334,6 +345,8 @@ jobs: -DBUILD_SHARED_LIBS=FALSE^ -DOPENDDS_ACE_TAO_SRC=${{ github.workspace }}\OpenDDS\build\ACE_TAO^ -DOPENDDS_MPC=${{ github.workspace }}\MPC^ + -DOPENDDS_XERCES3=${{ env.VCPKG_INSTALLED_DIR }}/x64-windows^ + -DOPENDDS_OPENSSL=${{ env.VCPKG_INSTALLED_DIR }}/x64-windows^ -DOPENDDS_BUILD_TESTS=TRUE^ -DOPENDDS_CMAKE_VERBOSE=all - uses: ammaraskar/msvc-problem-matcher@0.3.0 @@ -389,6 +402,8 @@ jobs: -DBUILD_SHARED_LIBS=TRUE^ -DOPENDDS_ACE_TAO_SRC=${{ github.workspace }}\OpenDDS\build\ACE_TAO^ -DOPENDDS_MPC=${{ github.workspace }}\MPC^ + -DOPENDDS_XERCES3=${{ env.VCPKG_INSTALLED_DIR }}/x64-windows^ + -DOPENDDS_OPENSSL=${{ env.VCPKG_INSTALLED_DIR }}/x64-windows^ -DOPENDDS_BUILD_TESTS=TRUE^ -DOPENDDS_CMAKE_VERBOSE=all - uses: ammaraskar/msvc-problem-matcher@0.3.0 @@ -408,6 +423,15 @@ jobs: runs-on: windows-2022 steps: + - name: setup for run-vcpkg + shell: bash + run: | + echo '{ "name": "opendds", "version-string": "github-actions", "dependencies": [ "openssl", "xerces-c" ] }' > vcpkg.json + - name: install openssl & xerces-c + uses: lukka/run-vcpkg@v11 + with: + vcpkgGitCommitId: '${{ env.VCPKG_GIT_COMMIT }}' + runVcpkgInstall: true - name: Checkout OpenDDS uses: actions/checkout@v4 with: @@ -434,6 +458,8 @@ jobs: -DBUILD_SHARED_LIBS=FALSE^ -DOPENDDS_ACE_TAO_SRC=${{ github.workspace }}\OpenDDS\build\ACE_TAO^ -DOPENDDS_MPC=${{ github.workspace }}\MPC^ + -DOPENDDS_XERCES3=${{ env.VCPKG_INSTALLED_DIR }}/x64-windows^ + -DOPENDDS_OPENSSL=${{ env.VCPKG_INSTALLED_DIR }}/x64-windows^ -DOPENDDS_BUILD_TESTS=TRUE^ -DOPENDDS_CMAKE_VERBOSE=all - uses: ammaraskar/msvc-problem-matcher@0.3.0 diff --git a/cmake/ace_group.cmake b/cmake/ace_group.cmake index a9d2218368b..6105b1b9733 100644 --- a/cmake/ace_group.cmake +++ b/cmake/ace_group.cmake @@ -38,16 +38,6 @@ _opendds_group_exe(ace_gperf EXTRA_BIN_DIRS "${TAO_BIN_DIR}" ) -if(OPENDDS_XERCES3) - find_package(XercesC PATHS "${OPENDDS_XERCES3}" NO_DEFAULT_PATH QUIET) - if(NOT XercesC_FOUND) - find_package(XercesC QUIET) - endif() - if(NOT XercesC_FOUND) - message(FATAL_ERROR "Could not find XercesC") - endif() -endif() - function(_opendds_vs_force_static) # Make sure the MSVC runtime library, which is similar to libc of other # systems, is the same kind everywhere. Normally we shouldn't make global diff --git a/cmake/build_ace_tao.cmake b/cmake/build_ace_tao.cmake index 91163af79cb..c011484d426 100644 --- a/cmake/build_ace_tao.cmake +++ b/cmake/build_ace_tao.cmake @@ -40,9 +40,14 @@ execute_process( # Get the C++ standard OpenDDS is going to be built with. We are going to force # the ACE/TAO build to use the same standard. -set(opendds_idl_std "$") -set(dcps_std "$") -set(std "$,${dcps_std},${opendds_idl_std}>") +set(_opendds_idl_std "$") +set(_opendds_dcps_std "$") +set(_opendds_std "$,${_opendds_dcps_std},${_opendds_idl_std}>") + +set(_build_cmd "${CMAKE_COMMAND}" -E env "ACE_ROOT=${OPENDDS_ACE}" "TAO_ROOT=${OPENDDS_TAO}") +if(_OPENDDS_XERCES3_FOR_ACE) + list(APPEND _build_cmd "XERCESCROOT=${_OPENDDS_XERCES3_FOR_ACE}") +endif() if(_OPENDDS_MPC_TYPE STREQUAL gnuace) execute_process( @@ -74,20 +79,23 @@ if(_OPENDDS_MPC_TYPE STREQUAL gnuace) list(APPEND byproducts "${file}") endforeach() - set(make_cmd "${CMAKE_COMMAND}" -E env "ACE_ROOT=${OPENDDS_ACE}" "TAO_ROOT=${OPENDDS_TAO}") if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") - list(APPEND make_cmd "$(MAKE)") + list(APPEND _build_cmd "$(MAKE)") else() find_program(make_exe NAMES gmake make) cmake_host_system_information(RESULT core_count QUERY NUMBER_OF_LOGICAL_CORES) - list(APPEND make_cmd "${make_exe}" "-j${core_count}") + list(APPEND _build_cmd "${make_exe}" "-j${core_count}") endif() + list(APPEND _build_cmd + "opendds_cmake_std=$,-std=c++${_opendds_std},>" + ) + ExternalProject_Add(build_ace_tao SOURCE_DIR "${OPENDDS_ACE_TAO_SRC}" CONFIGURE_COMMAND "${CMAKE_COMMAND}" -E echo "Already configured" BUILD_IN_SOURCE TRUE - BUILD_COMMAND ${make_cmd} "opendds_cmake_std=$,-std=c++${std},>" + BUILD_COMMAND ${_build_cmd} BUILD_BYPRODUCTS ${byproducts} USES_TERMINAL_BUILD TRUE # Needed for Ninja to show the ACE/TAO build INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "No install step" @@ -132,16 +140,17 @@ elseif(_OPENDDS_MPC_TYPE MATCHES "^vs") endif() endforeach() + list(APPEND _build_cmd + MSBuild "${sln}" "-maxcpucount" + "-property:Configuration=$,Platform=${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}" + "$,-property:LanguageStandard=stdcpp${_opendds_std},>" + ) + ExternalProject_Add(build_ace_tao SOURCE_DIR "${OPENDDS_ACE_TAO_SRC}" CONFIGURE_COMMAND "${CMAKE_COMMAND}" -E echo "Already configured" BUILD_IN_SOURCE TRUE - BUILD_COMMAND - "${CMAKE_COMMAND}" -E env "ACE_ROOT=${OPENDDS_ACE}" "TAO_ROOT=${OPENDDS_TAO}" - MSBuild "${sln}" - "-property:Configuration=$,Platform=${CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE}" - "$,-property:LanguageStandard=stdcpp${std},>" - "-maxcpucount" + BUILD_COMMAND ${_build_cmd} BUILD_BYPRODUCTS ${byproducts} USES_TERMINAL_BUILD TRUE # Needed for Ninja to show the ACE/TAO build INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "No install step" diff --git a/cmake/configure_ace_tao.pl b/cmake/configure_ace_tao.pl index 837398476af..b34b899c2b6 100755 --- a/cmake/configure_ace_tao.pl +++ b/cmake/configure_ace_tao.pl @@ -34,6 +34,8 @@ push(@opts, "$key=s"); } push(@opts, "macro-line=s@"); +my %env; +push(@opts, "env=s%" => %env); if (!GetOptions(\%values, @opts)) { exit(1); } @@ -120,6 +122,13 @@ sub read_file { $ENV{MPC_ROOT} = File::Spec->rel2abs($values{mpc}); $ENV{ACE_ROOT} = File::Spec->rel2abs($values{ace}); $ENV{TAO_ROOT} = File::Spec->rel2abs($values{tao}); +if ($values{'env'}) { + for my $name (keys(%{$values{'env'}})) { + my $value = $values{env}->{$name}; + print("env: $name=$value\n"); + $ENV{$name} = $value; + } +} my $mwc_name = 'ACE_TAO_for_OpenDDS.mwc'; my $mwc_src = $values{'workspace-file'} // "$FindBin::RealBin/../$mwc_name"; my $mwc = "$values{src}/$mwc_name"; diff --git a/cmake/init.cmake b/cmake/init.cmake index baa1b5743c9..590399a76f6 100644 --- a/cmake/init.cmake +++ b/cmake/init.cmake @@ -530,3 +530,16 @@ if(NOT DEFINED OPENDDS_SUPPORTS_SHMEM) set(OPENDDS_SUPPORTS_SHMEM TRUE) endif() endif() + +# This should be in ace_group.cmake, but it's needed by build_ace_tao.cmake. +if(OPENDDS_XERCES3) + find_package(XercesC PATHS "${OPENDDS_XERCES3}" NO_DEFAULT_PATH QUIET) + if(NOT XercesC_FOUND) + find_package(XercesC QUIET) + endif() + if(NOT XercesC_FOUND) + message(FATAL_ERROR "Could not find XercesC") + endif() + get_filename_component(_opendds_xerces3_for_ace "${XercesC_INCLUDE_DIRS}" DIRECTORY) + set(_OPENDDS_XERCES3_FOR_ACE "${_opendds_xerces3_for_ace}" CACHE PATH "" FORCE) +endif() diff --git a/dds/DCPS/QOS_XML_Handler/XML_String_Intf.h b/dds/DCPS/QOS_XML_Handler/XML_String_Intf.h index 1f7789f16a0..e736a17d3e9 100644 --- a/dds/DCPS/QOS_XML_Handler/XML_String_Intf.h +++ b/dds/DCPS/QOS_XML_Handler/XML_String_Intf.h @@ -28,10 +28,10 @@ namespace XML class XML_Error_Handler; } -XERCES_CPP_NAMESPACE_BEGIN +namespace XERCES_CPP_NAMESPACE { class XercesDOMParser; class DOMDocument; -XERCES_CPP_NAMESPACE_END +} OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL diff --git a/dds/DCPS/ValueDispatcher.h b/dds/DCPS/ValueDispatcher.h index f09587576bb..ca723287be2 100644 --- a/dds/DCPS/ValueDispatcher.h +++ b/dds/DCPS/ValueDispatcher.h @@ -9,6 +9,8 @@ #include "TypeSupportImpl.h" #include "ValueReader.h" #include "ValueWriter.h" +#include "Sample.h" +#include "debug.h" OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL @@ -21,8 +23,8 @@ struct OpenDDS_Dcps_Export ValueDispatcher { virtual void* new_value() const = 0; virtual void delete_value(void* data) const = 0; - virtual bool read(ValueReader& value_reader, void* data) const = 0; - virtual bool write(ValueWriter& value_writer, const void* data) const = 0; + virtual bool read(ValueReader& value_reader, void* data, Sample::Extent ext = Sample::Full) const = 0; + virtual bool write(ValueWriter& value_writer, const void* data, Sample::Extent ext = Sample::Full) const = 0; virtual DDS::InstanceHandle_t register_instance_helper(DDS::DataWriter* dw, const void* data) const = 0; virtual DDS::ReturnCode_t write_helper(DDS::DataWriter* dw, const void* data, DDS::InstanceHandle_t inst) const = 0; @@ -45,17 +47,40 @@ struct ValueDispatcher_T : public virtual ValueDispatcher { delete tbd; } - virtual bool read(ValueReader& value_reader, void* data) const + typedef typename OpenDDS::DCPS::DDSTraits TraitsType; + + virtual bool read(ValueReader& value_reader, void* data, Sample::Extent ext = Sample::Full) const { - return vread(value_reader, *static_cast(data)); + switch (ext) { + case Sample::Full: + return vread(value_reader, *static_cast(data)); + case Sample::KeyOnly: + return vread(value_reader, *static_cast*>(data)); + default: + if (log_level >= LogLevel::Notice) { + ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: ValueDispatcher_T<%C>::read:" + " Called with Sample::Extent NestedKeyOnly\n", TraitsType::type_name())); + } + return false; + } } - virtual bool write(ValueWriter& value_writer, const void* data) const + virtual bool write(ValueWriter& value_writer, const void* data, Sample::Extent ext = Sample::Full) const { - return vwrite(value_writer, *static_cast(data)); + switch (ext) { + case Sample::Full: + return vwrite(value_writer, *static_cast(data)); + case Sample::KeyOnly: + return vwrite(value_writer, *static_cast*>(data)); + default: + if (log_level >= LogLevel::Notice) { + ACE_ERROR((LM_NOTICE, "(%P|%t) NOTICE: ValueDispatcher_T<%C>::write:" + " Called with Sample::Extent NestedKeyOnly\n", TraitsType::type_name())); + } + return false; + } } - typedef typename OpenDDS::DCPS::DDSTraits TraitsType; typedef typename TraitsType::DataWriterType DataWriterType; virtual DDS::InstanceHandle_t register_instance_helper(DDS::DataWriter* dw, const void* data) const diff --git a/dds/DCPS/XTypes/DynamicDataImpl.cpp b/dds/DCPS/XTypes/DynamicDataImpl.cpp index 0e1b4cb1cfc..a0f8487b833 100644 --- a/dds/DCPS/XTypes/DynamicDataImpl.cpp +++ b/dds/DCPS/XTypes/DynamicDataImpl.cpp @@ -5042,10 +5042,6 @@ bool serialized_size_dynamic_union(const Encoding& encoding, size_t& size, using namespace OpenDDS::XTypes; const DDS::DynamicType_var type = union_data->type(); const DDS::DynamicType_var base_type = get_base_type(type); - if (ext == Sample::KeyOnly && !has_explicit_keys(base_type)) { - // nothing is serialized (not even a delimiter) for key-only serialization when there is no @key - return true; - } DDS::TypeDescriptor_var td; if (!get_type_descriptor(base_type, td)) { @@ -5058,6 +5054,10 @@ bool serialized_size_dynamic_union(const Encoding& encoding, size_t& size, serialized_size_delimiter(encoding, size); } + if (ext == Sample::KeyOnly && !has_explicit_keys(base_type)) { + return true; + } + // Discriminator size_t mutable_running_total = 0; DDS::DynamicType_var disc_type = get_base_type(td->discriminator_type()); @@ -5704,10 +5704,6 @@ bool serialize_dynamic_union(Serializer& ser, DDS::DynamicData_ptr data, Sample: using namespace OpenDDS::XTypes; const DDS::DynamicType_var type = data->type(); const DDS::DynamicType_var base_type = get_base_type(type); - if (ext == Sample::KeyOnly && !has_explicit_keys(base_type)) { - // nothing is serialized (not even a delimiter) for key-only serialization when there is no @key - return true; - } DDS::TypeDescriptor_var td; if (!get_type_descriptor(base_type, td)) { @@ -5725,6 +5721,10 @@ bool serialize_dynamic_union(Serializer& ser, DDS::DynamicData_ptr data, Sample: } } + if (ext == Sample::KeyOnly && !has_explicit_keys(base_type)) { + return true; + } + // Discriminator DDS::DynamicTypeMember_var dtm; if (base_type->get_member(dtm, DISCRIMINATOR_ID) != DDS::RETCODE_OK) { diff --git a/dds/idl/dds_generator.h b/dds/idl/dds_generator.h index d09d7a6a9bb..e6ca05b9a09 100644 --- a/dds/idl/dds_generator.h +++ b/dds/idl/dds_generator.h @@ -1445,8 +1445,27 @@ inline std::string type_kind(AST_Type* type) } } +inline +FieldFilter nested(FieldFilter filter_kind) +{ + return filter_kind == FieldFilter_KeyOnly ? FieldFilter_NestedKeyOnly : filter_kind; +} + +inline +bool has_discriminator(AST_Union* u, FieldFilter filter_kind) +{ + return be_global->union_discriminator_is_key(u) + || filter_kind == FieldFilter_NestedKeyOnly + || filter_kind == FieldFilter_All; +} + +// TODO: Add more fine-grained control of "const" string for the wrapper type and wrapped type. +// Currently, there is a single bool to control both; that is, either both are "const" or +// none is "const". But sometimes, we want something like "const KeyOnly&", and +// not "const KeyOnly&" or "KeyOnly&". + /// Handling wrapping and unwrapping references in the wrapper types: -/// NestedKeyOnly, IDL::DistinctType, and *_forany. +/// NestedKeyOnly, KeyOnly, IDL::DistinctType, and *_forany. struct RefWrapper { const bool cpp11_; AST_Type* const type_; @@ -1456,6 +1475,7 @@ struct RefWrapper { const std::string fieldref_; const std::string local_; bool is_const_; + FieldFilter field_filter_; bool nested_key_only_; bool classic_array_copy_; bool dynamic_data_adapter_; @@ -1470,6 +1490,7 @@ struct RefWrapper { , to_wrap_(strip_shift_op(to_wrap)) , shift_op_(get_shift_op(to_wrap)) , is_const_(is_const) + , field_filter_(FieldFilter_All) , nested_key_only_(false) , classic_array_copy_(false) , dynamic_data_adapter_(false) @@ -1488,6 +1509,7 @@ struct RefWrapper { , fieldref_(strip_shift_op(fieldref)) , local_(local) , is_const_(is_const) + , field_filter_(FieldFilter_All) , nested_key_only_(false) , classic_array_copy_(false) , dynamic_data_adapter_(false) @@ -1508,8 +1530,9 @@ struct RefWrapper { const bool forany = classic_array_copy_ || needs_forany(type_); const bool distinct_type = needs_distinct_type(type_); needs_dda_tag_ = dynamic_data_adapter_ && (forany || distinct_type); - nested_key_only_ = nested_key_only_ && - needs_nested_key_only(typedef_node_ ? typedef_node_ : type_); + // If field_filter_ is set, this object is being used for vwrite or vread generator. + nested_key_only_ = field_filter_ == FieldFilter_NestedKeyOnly || + (nested_key_only_ && needs_nested_key_only(typedef_node_ ? typedef_node_ : type_)); wrapped_type_name_ = type_name_; bool by_ref = true; @@ -1546,9 +1569,12 @@ struct RefWrapper { ref_ = var_name; } + if (field_filter_ == FieldFilter_KeyOnly) { + wrapped_type_name_ = std::string("KeyOnly<") + const_str + wrapped_type_name_ + ">"; + } + if (nested_key_only_) { - wrapped_type_name_ = - std::string("NestedKeyOnly<") + const_str + wrapped_type_name_ + ">"; + wrapped_type_name_ = std::string("NestedKeyOnly<") + const_str + wrapped_type_name_ + ">"; value_access_post_ = ".value" + value_access_post_; const std::string nko_arg = "(" + ref_ + ")"; if (is_const_) { @@ -1693,4 +1719,14 @@ struct RefWrapper { } }; +inline +std::string key_only_type_name(AST_Type* type, const std::string& type_name, + FieldFilter field_filter, bool writing) +{ + RefWrapper wrapper(type, type_name, "", writing ? true : false); + wrapper.field_filter_ = field_filter; + const bool has_wrapper = field_filter != FieldFilter_All; + return (has_wrapper && !writing ? "const " : "") + wrapper.done().wrapped_type_name(); +} + #endif diff --git a/dds/idl/marshal_generator.cpp b/dds/idl/marshal_generator.cpp index d5588ccbee3..e2fd0c9a93a 100644 --- a/dds/idl/marshal_generator.cpp +++ b/dds/idl/marshal_generator.cpp @@ -1565,7 +1565,7 @@ bool marshal_generator::gen_typedef(AST_Typedef* node, UTL_ScopedName* name, AST namespace { // common to both fields (in structs) and branches (in unions) - string findSizeCommon(const std::string& indent, AST_Decl*field, const string& name, + string findSizeCommon(const std::string& indent, AST_Decl* field, const string& name, AST_Type* type, const string& prefix, bool wrap_nested_key_only, Intro& intro, const string& = "") // same sig as streamCommon { @@ -3379,9 +3379,9 @@ namespace { serialized_size.addArg("uni", "const " + wrapper + ""); serialized_size.endArgs(); - if (has_key) { - marshal_generator::generate_dheader_code(" serialized_size_delimiter(encoding, size);\n", not_final, false); + marshal_generator::generate_dheader_code(" serialized_size_delimiter(encoding, size);\n", not_final, false); + if (has_key) { if (exten == extensibilitykind_mutable) { be_global->impl_ << " size_t mutable_running_total = 0;\n" @@ -3409,16 +3409,16 @@ namespace { insertion.addArg("uni", wrapper + ""); insertion.endArgs(); - if (has_key) { - be_global->impl_ << - " const Encoding& encoding = strm.encoding();\n" - " ACE_UNUSED_ARG(encoding);\n"; - marshal_generator::generate_dheader_code( - " serialized_size(encoding, total_size, uni);\n" - " if (!strm.write_delimiter(total_size)) {\n" - " return false;\n" - " }\n", not_final); + be_global->impl_ << + " const Encoding& encoding = strm.encoding();\n" + " ACE_UNUSED_ARG(encoding);\n"; + marshal_generator::generate_dheader_code( + " serialized_size(encoding, total_size, uni);\n" + " if (!strm.write_delimiter(total_size)) {\n" + " return false;\n" + " }\n", not_final); + if (has_key) { // EMHEADER for discriminator if (exten == extensibilitykind_mutable) { be_global->impl_ << @@ -3452,16 +3452,16 @@ namespace { extraction.addArg("uni", wrapper + "<" + cxx + ">"); extraction.endArgs(); - if (has_key) { - // DHEADER - be_global->impl_ << - " const Encoding& encoding = strm.encoding();\n" - " ACE_UNUSED_ARG(encoding);\n"; - marshal_generator::generate_dheader_code( - " if (!strm.read_delimiter(total_size)) {\n" - " return false;\n" - " }\n", not_final); + // DHEADER + be_global->impl_ << + " const Encoding& encoding = strm.encoding();\n" + " ACE_UNUSED_ARG(encoding);\n"; + marshal_generator::generate_dheader_code( + " if (!strm.read_delimiter(total_size)) {\n" + " return false;\n" + " }\n", not_final); + if (has_key) { if (exten == extensibilitykind_mutable) { // EMHEADER for discriminator be_global->impl_ << @@ -3739,7 +3739,9 @@ bool marshal_generator::gen_union(AST_Union* node, UTL_ScopedName* name, } gen_union_key_serializers(node, FieldFilter_NestedKeyOnly); - gen_union_key_serializers(node, FieldFilter_KeyOnly); + if (be_global->is_topic_type(node)) { + gen_union_key_serializers(node, FieldFilter_KeyOnly); + } TopicKeys keys(node); return generate_marshal_traits(node, cxx, exten, keys); diff --git a/dds/idl/value_reader_generator.cpp b/dds/idl/value_reader_generator.cpp index 511f02ae9cd..1085e8c2999 100644 --- a/dds/idl/value_reader_generator.cpp +++ b/dds/idl/value_reader_generator.cpp @@ -20,7 +20,8 @@ using namespace AstTypeClassification; namespace { void generate_read(const std::string& expression, const std::string& accessor, - AST_Type* type, const std::string& idx, int level = 1); + const std::string& field_name, AST_Type* type, const std::string& idx, + int level = 1, FieldFilter field_filter = FieldFilter_All); std::string primitive_type(AST_PredefinedType::PredefinedType pt) { @@ -62,8 +63,8 @@ namespace { } } - void array_helper(const std::string& expression, AST_Array* array, - size_t dim_idx, const std::string& idx, int level) + void array_helper(const std::string& expression, AST_Array* array, size_t dim_idx, + const std::string& idx, int level, FieldFilter filter_kind) { const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11; const std::string indent(level * 2, ' '); @@ -80,7 +81,7 @@ namespace { indent << "for (" << (use_cxx11 ? "size_t " : "unsigned int ") << idx << " = 0; " << idx << " != " << dim << "; ++" << idx << ") {\n" << indent << " if (!value_reader.begin_element()) return false;\n"; - array_helper(expression + "[" + idx + "]", array, dim_idx + 1, idx + "i", level + 1); + array_helper(expression + "[" + idx + "]", array, dim_idx + 1, idx + "i", level + 1, filter_kind); be_global->impl_ << indent << " if (!value_reader.end_element()) return false;\n" << indent << "}\n" << @@ -99,13 +100,13 @@ namespace { indent << "if (!value_reader.end_array()) return false;\n"; } else { - generate_read(expression, "", array->base_type(), idx + "i", level); + generate_read(expression, "", "elem", array->base_type(), idx + "i", level, nested(filter_kind)); } } } void sequence_helper(const std::string& expression, AST_Sequence* sequence, - const std::string& idx, int level) + const std::string& idx, int level, FieldFilter filter_kind) { // TODO: Take advantage of the size. const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11; @@ -128,7 +129,8 @@ namespace { } be_global->impl_ << indent << " if (!value_reader.begin_element()) return false;\n"; - generate_read(expression + "[" + idx + "]", "", sequence->base_type(), idx + "i", level + 1); + generate_read(expression + "[" + idx + "]", "", "elem", sequence->base_type(), + idx + "i", level + 1, nested(filter_kind)); be_global->impl_ << indent << " if (!value_reader.end_element()) return false;\n" << indent << "}\n" << @@ -136,19 +138,20 @@ namespace { } void generate_read(const std::string& expression, const std::string& accessor, - AST_Type* type, const std::string& idx, int level) + const std::string& field_name, AST_Type* type, const std::string& idx, + int level, FieldFilter filter_kind) { AST_Type* const actual = resolveActualType(type); const Classification c = classify(actual); if (c & CL_SEQUENCE) { AST_Sequence* const sequence = dynamic_cast(actual); - sequence_helper(expression + accessor, sequence, idx, level); + sequence_helper(expression + accessor, sequence, idx, level, filter_kind); return; } else if (c & CL_ARRAY) { AST_Array* const array = dynamic_cast(actual); - array_helper(expression + accessor, array, 0, idx, level); + array_helper(expression + accessor, array, 0, idx, level, filter_kind); return; } @@ -186,9 +189,29 @@ namespace { indent << "if (!value_reader.read_" << primitive_type(pt) << '(' << expression << accessor << ")) return false;\n"; } } else { + std::string value_expr = expression + accessor; + if (!(c & CL_ENUM)) { + const std::string type_name = scoped(type->name()); + switch (filter_kind) { + case FieldFilter_NestedKeyOnly: + value_expr = field_name + "_nested_key_only"; + be_global->impl_ << + indent << "const NestedKeyOnly<" << type_name << "> " << + value_expr << "(" << expression << accessor << ");\n"; + break; + case FieldFilter_KeyOnly: + value_expr = field_name + "_key_only"; + be_global->impl_ << + indent << "const KeyOnly<" << type_name << "> " << + value_expr << "(" << expression << accessor << ");\n"; + break; + default: + break; + } + } + be_global->impl_ << - indent << "if (!vread(value_reader, " << expression << accessor << - ")) return false;\n"; + indent << "if (!vread(value_reader, " << value_expr << ")) return false;\n"; } } @@ -211,12 +234,109 @@ namespace { be_global->impl_ << " if (!value_reader.begin_union_member()) return false;\n" " " << decl << " bv;\n"; - generate_read("bv", "", type, "i", 2); + generate_read("bv", "", field_name, type, "i", 2); be_global->impl_ << " value." << field_name << "(bv" << ((c & CL_STRING) ? ".c_str()" : "") << ");\n" << " if (!value_reader.end_union_member()) return false;\n"; return ""; } + + bool gen_struct_i(AST_Structure* node, const std::string& type_name, + bool use_cxx11, ExtensibilityKind ek, FieldFilter field_filter) + { + const std::string wrapped_name = key_only_type_name(node, type_name, field_filter, false); + Function read("vread", "bool"); + read.addArg("value_reader", "OpenDDS::DCPS::ValueReader&"); + read.addArg("value", wrapped_name); + read.endArgs(); + + be_global->impl_ << + " static const ListMemberHelper::Pair pairs[] = {"; + + const std::string value_prefix = field_filter == FieldFilter_All ? "value." : "value.value."; + const Fields fields(node, field_filter); + + for (Fields::Iterator it = fields.begin(); it != fields.end(); ++it) { + AST_Field* const field = *it; + be_global->impl_ << + "{\"" << canonical_name(field) << "\"," << be_global->get_id(field) << "},"; + } + + be_global->impl_ << + "{0,0}};\n" + " ListMemberHelper helper(pairs);\n"; + + be_global->impl_ << + " if (!value_reader.begin_struct(" << extensibility_kind(ek) << ")) return false;\n" + " XTypes::MemberId member_id;\n" + " while (value_reader.members_remaining()) {\n" + " if (!value_reader.begin_struct_member(member_id, helper)) return false;\n" + " switch (member_id) {\n"; + + for (Fields::Iterator it = fields.begin(); it != fields.end(); ++it) { + AST_Field* const field = *it; + const std::string field_name = field->local_name()->get_string(); + be_global->impl_ << + " case " << be_global->get_id(field) << ": {\n"; + generate_read(value_prefix + field_name, use_cxx11 ? "()" : "", field_name, + field->field_type(), "i", 3, nested(field_filter)); + be_global->impl_ << + " break;\n" + " }\n"; + } + + be_global->impl_ << + " }\n" + " if (!value_reader.end_struct_member()) return false;\n" + " }\n" + " if (!value_reader.end_struct()) return false;\n" + " return true;\n"; + return true; + } + + bool gen_union_i(AST_Union* u, const std::string& type_name, + const std::vector& branches, + AST_Type* discriminator, ExtensibilityKind ek, FieldFilter filter_kind) + { + const std::string wrapped_name = key_only_type_name(u, type_name, filter_kind, false); + Function read("vread", "bool"); + read.addArg("value_reader", "OpenDDS::DCPS::ValueReader&"); + read.addArg("value", wrapped_name); + read.endArgs(); + + const std::string value_prefix = filter_kind == FieldFilter_All ? "value." : "value.value."; + be_global->impl_ << + " if (!value_reader.begin_union(" << extensibility_kind(ek) << ")) return false;\n"; + + const bool has_disc = has_discriminator(u, filter_kind); + if (has_disc) { + be_global->impl_ << + " if (!value_reader.begin_discriminator()) return false;\n" + " " << scoped(discriminator->name()) << " d;\n"; + generate_read("d", "", "disc", discriminator, "i", 1, nested(filter_kind)); + be_global->impl_ << + " if (!value_reader.end_discriminator()) return false;\n"; + } + + if (filter_kind == FieldFilter_All) { + generateSwitchForUnion(u, "d", branch_helper, branches, + discriminator, "", "", type_name.c_str(), + false, false); + be_global->impl_ << + " value._d(d);\n"; + } else if (has_disc) { + // Assigning the discriminator directly before a branch is set doesn't strictly + // conform to the IDL-to-C++ mapping. However, this case cares only about the + // discriminator, i.e. KeyOnly or NestedKeyOnly samples, so it's probably fine. + be_global->impl_ << + " value.value._d(d);\n"; + } + + be_global->impl_ << + " if (!value_reader.end_union()) return false;\n" + " return true;\n"; + return true; + } } bool value_reader_generator::gen_enum(AST_Enum*, @@ -249,7 +369,7 @@ bool value_reader_generator::gen_typedef(AST_Typedef*, bool value_reader_generator::gen_struct(AST_Structure* node, UTL_ScopedName* name, - const std::vector& fields, + const std::vector& /*fields*/, AST_Type::SIZE_TYPE, const char*) { @@ -258,64 +378,22 @@ bool value_reader_generator::gen_struct(AST_Structure* node, const std::string type_name = scoped(name); const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11; - const std::string accessor = use_cxx11 ? "()" : ""; - - { - NamespaceGuard guard; + const ExtensibilityKind ek = be_global->extensibility(node); - Function read("vread", "bool"); - read.addArg("value_reader", "OpenDDS::DCPS::ValueReader&"); - read.addArg("value", type_name + "&"); - read.endArgs(); - - be_global->impl_ << - " static const ListMemberHelper::Pair pairs[] = {"; + NamespaceGuard guard; + if (!gen_struct_i(node, type_name, use_cxx11, ek, FieldFilter_All) || + !gen_struct_i(node, type_name, use_cxx11, ek, FieldFilter_NestedKeyOnly)) { + return false; + } - for (size_t i = 0; i != fields.size(); ++i) { - if (i) { - be_global->impl_ << ','; - } - const std::string idl_name = canonical_name(fields[i]); - be_global->impl_ << - '{' << '"' << idl_name << '"' << ',' << be_global->get_id(fields[i]) << '}'; + if (be_global->is_topic_type(node)) { + if (!gen_struct_i(node, type_name, use_cxx11, ek, FieldFilter_KeyOnly)) { + return false; } - - be_global->impl_ << - ",{0,0}};\n" - " ListMemberHelper helper(pairs);\n"; - - const ExtensibilityKind ek = be_global->extensibility(node); - be_global->impl_ << - " if (!value_reader.begin_struct(" << extensibility_kind(ek) << ")) return false;\n" - " XTypes::MemberId member_id;\n" - " while (value_reader.members_remaining()) {\n" - " if (!value_reader.begin_struct_member(member_id, helper)) return false;\n" - " switch (member_id) {\n"; - - for (std::vector::const_iterator pos = fields.begin(), limit = fields.end(); - pos != limit; ++pos) { - AST_Field* const field = *pos; - const std::string field_name = field->local_name()->get_string(); - be_global->impl_ << - " case " << be_global->get_id(field) << ": {\n"; - generate_read("value." + field_name, accessor, field->field_type(), "i", 3); - be_global->impl_ << - " break;\n" - " }\n"; - } - - be_global->impl_ << - " }\n" - " if (!value_reader.end_struct_member()) return false;\n" - " }\n" - " if (!value_reader.end_struct()) return false;\n" - " return true;\n"; } - return true; } - bool value_reader_generator::gen_union(AST_Union* u, UTL_ScopedName* name, const std::vector& branches, @@ -326,32 +404,18 @@ bool value_reader_generator::gen_union(AST_Union* u, be_global->add_include("dds/DCPS/ValueReader.h", BE_GlobalData::STREAM_H); const std::string type_name = scoped(name); + const ExtensibilityKind ek = be_global->extensibility(u); - { - NamespaceGuard guard; - - Function read("vread", "bool"); - read.addArg("value_reader", "OpenDDS::DCPS::ValueReader&"); - read.addArg("value", type_name + "&"); - read.endArgs(); - - const ExtensibilityKind ek = be_global->extensibility(u); - be_global->impl_ << - " if (!value_reader.begin_union(" << extensibility_kind(ek) << ")) return false;\n" - " if (!value_reader.begin_discriminator()) return false;\n" - " " << scoped(discriminator->name()) << " d;\n"; - generate_read("d", "", discriminator, "i", 2); - be_global->impl_ << - " if (!value_reader.end_discriminator()) return false;\n"; - - generateSwitchForUnion(u, "d", branch_helper, branches, - discriminator, "", "", type_name.c_str(), - false, false); - be_global->impl_ << - " value._d(d);\n" - " if (!value_reader.end_union()) return false;\n" - " return true;\n"; + NamespaceGuard guard; + if (!gen_union_i(u, type_name, branches, discriminator, ek, FieldFilter_All) || + !gen_union_i(u, type_name, branches, discriminator, ek, FieldFilter_NestedKeyOnly)) { + return false; } + if (be_global->is_topic_type(u)) { + if (!gen_union_i(u, type_name, branches, discriminator, ek, FieldFilter_KeyOnly)) { + return false; + } + } return true; } diff --git a/dds/idl/value_writer_generator.cpp b/dds/idl/value_writer_generator.cpp index 62e31306f8c..4c27ffcf899 100644 --- a/dds/idl/value_writer_generator.cpp +++ b/dds/idl/value_writer_generator.cpp @@ -18,7 +18,9 @@ using namespace AstTypeClassification; namespace { - void generate_write(const std::string& expression, AST_Type* type, const std::string& idx, int level = 1); + void generate_write(const std::string& expression, const std::string& field_name, + AST_Type* type, const std::string& idx, int level = 1, + FieldFilter field_filter = FieldFilter_All); std::string primitive_type(AST_PredefinedType::PredefinedType pt) { @@ -60,8 +62,8 @@ namespace { } } - void array_helper(const std::string& expression, AST_Array* array, - size_t dim_idx, const std::string& idx, int level) + void array_helper(const std::string& expression, AST_Array* array, size_t dim_idx, + const std::string& idx, int level, FieldFilter filter_kind) { const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11; const std::string indent(level * 2, ' '); @@ -83,7 +85,7 @@ namespace { indent << " if (!value_writer.begin_element(static_cast(" << idx << "))) {\n" << indent << " return false;\n" << indent << " }\n"; - array_helper(expression + "[" + idx + "]", array, dim_idx + 1, idx + "i", level + 1); + array_helper(expression + "[" + idx + "]", array, dim_idx + 1, idx + "i", level + 1, filter_kind); be_global->impl_ << indent << " if (!value_writer.end_element()) {\n" << indent << " return false;\n" << @@ -114,13 +116,13 @@ namespace { indent << "}\n"; } else { - generate_write(expression, array->base_type(), idx + "i", level); + generate_write(expression, "elem", array->base_type(), idx + "i", level, nested(filter_kind)); } } } void sequence_helper(const std::string& expression, AST_Sequence* sequence, - const std::string& idx, int level) + const std::string& idx, int level, FieldFilter filter_kind) { const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11; const char* const length_func = use_cxx11 ? "size" : "length"; @@ -161,7 +163,7 @@ namespace { indent << " if (!value_writer.begin_element(static_cast(" << idx << "))) {\n" << indent << " return false;\n" << indent << " }\n"; - generate_write(expression + "[" + idx + "]", base_type, idx + "i", level + 1); + generate_write(expression + "[" + idx + "]", "elem", base_type, idx + "i", level + 1, nested(filter_kind)); be_global->impl_ << indent << " if (!value_writer.end_element()) {\n" << indent << " return false;\n" << @@ -175,49 +177,69 @@ namespace { indent << "}\n"; } - void generate_write(const std::string& expression, AST_Type* type, const std::string& idx, int level) + void generate_write(const std::string& expression, const std::string& field_name, + AST_Type* type, const std::string& idx, int level, FieldFilter field_filter) { AST_Type* const actual = resolveActualType(type); const Classification c = classify(actual); if (c & CL_SEQUENCE) { AST_Sequence* const sequence = dynamic_cast(actual); - sequence_helper(expression, sequence, idx, level); + sequence_helper(expression, sequence, idx, level, field_filter); return; } else if (c & CL_ARRAY) { AST_Array* const array = dynamic_cast(actual); - array_helper(expression, array, 0, idx, level); + array_helper(expression, array, 0, idx, level, field_filter); return; } - be_global->impl_ << std::string(level * 2, ' '); + const std::string indent(level * 2, ' '); if (c & CL_FIXED) { be_global->impl_ << - "if (!value_writer.write_fixed(" << expression << ".to_ace_fixed())) {\n" - " return false;\n" - "}\n"; + indent << "if (!value_writer.write_fixed(" << expression << ".to_ace_fixed())) {\n" << + indent << " return false;\n" << + indent << "}\n"; } else if (c & CL_STRING) { be_global->impl_ << - "if (!value_writer.write_" << ((c & CL_WIDE) ? "w" : "") << "string(" << expression << ")) {\n" - " return false;\n" - "}\n"; + indent << "if (!value_writer.write_" << ((c & CL_WIDE) ? "w" : "") << "string(" << expression << ")) {\n" << + indent << " return false;\n" << + indent << "}\n"; } else if (c & CL_PRIMITIVE) { const AST_PredefinedType::PredefinedType pt = dynamic_cast(actual)->pt(); be_global->impl_ << - "if (!value_writer.write_" << primitive_type(pt) << '(' << expression << ")) {\n" - " return false;\n" - "}\n"; + indent << "if (!value_writer.write_" << primitive_type(pt) << '(' << expression << ")) {\n" << + indent << " return false;\n" << + indent << "}\n"; } else { + std::string value_expr = expression; + if (!(c & CL_ENUM)) { + const std::string type_name = scoped(type->name()); + switch (field_filter) { + case FieldFilter_NestedKeyOnly: + value_expr = field_name + "_nested_key_only"; + be_global->impl_ << + indent << "const NestedKeyOnly " << value_expr << "(" << expression << ");\n"; + break; + case FieldFilter_KeyOnly: + value_expr = field_name + "_key_only"; + be_global->impl_ << + indent << "const KeyOnly " << value_expr << "(" << expression << ");\n"; + break; + default: + break; + } + } + be_global->impl_ << - "if (!vwrite(value_writer, " << expression << ")) {\n" - " return false;\n" - "}\n"; + indent << "if (!vwrite(value_writer, " << value_expr << ")) {\n" << + indent << " return false;\n" << + indent << "}\n"; } } @@ -238,13 +260,95 @@ namespace { (must_understand ? "true" : "false") << ", \"" << canonical_name(branch) << "\", false, true))) {\n" " return false;\n" " }\n"; - generate_write("value." + field_name + "()", type, "i", 2); + generate_write("value." + field_name + "()", field_name, type, "i", 2); be_global->impl_ << " if (!value_writer.end_union_member()) {\n" " return false;\n" " }\n"; return ""; } + + bool gen_struct_i(AST_Structure* node, const std::string& type_name, + bool use_cxx11, ExtensibilityKind ek, FieldFilter field_filter) + { + const std::string wrapped_name = key_only_type_name(node, type_name, field_filter, true); + Function write("vwrite", "bool"); + write.addArg("value_writer", "OpenDDS::DCPS::ValueWriter&"); + write.addArg("value", wrapped_name); + write.endArgs(); + + const std::string value_prefix = field_filter == FieldFilter_All ? "value." : "value.value."; + const Fields fields(node, field_filter); + const FieldFilter nested_field_filter = nested(field_filter); + + be_global->impl_ << + " if (!value_writer.begin_struct(" << extensibility_kind(ek) << ")) {\n" + " return false;\n" + " }\n"; + for (Fields::Iterator i = fields.begin(); i != fields.end(); ++i) { + AST_Field* const field = *i; + const std::string field_name = field->local_name()->get_string(); + const std::string idl_name = canonical_name(field); + const OpenDDS::XTypes::MemberId id = be_global->get_id(field); + const bool must_understand = be_global->is_effectively_must_understand(field); + // TODO: Update the arguments for MemberParam when @optional is available. + be_global->impl_ << + " if (!value_writer.begin_struct_member(MemberParam(" << id << ", " << + (must_understand ? "true" : "false") << ", \"" << idl_name << "\", false, true))) {\n" + " return false;\n" + " }\n"; + generate_write(value_prefix + field_name + (use_cxx11 ? "()" : ""), field_name, + field->field_type(), "i", 1, nested_field_filter); + be_global->impl_ << + " if (!value_writer.end_struct_member()) {\n" + " return false;\n" + " }\n"; + } + be_global->impl_ << + " return value_writer.end_struct();\n"; + return true; + } + + bool gen_union_i(AST_Union* u, const std::string& type_name, + const std::vector& branches, + AST_Type* discriminator, ExtensibilityKind ek, FieldFilter filter_kind) + { + const std::string wrapped_name = key_only_type_name(u, type_name, filter_kind, true); + Function write("vwrite", "bool"); + write.addArg("value_writer", "OpenDDS::DCPS::ValueWriter&"); + write.addArg("value", wrapped_name); + write.endArgs(); + + const std::string value_prefix = filter_kind == FieldFilter_All ? "value." : "value.value."; + be_global->impl_ << + " if (!value_writer.begin_union(" << extensibility_kind(ek) << ")) {\n" + " return false;\n" + " }\n"; + + if (has_discriminator(u, filter_kind)) { + const bool must_understand = be_global->is_effectively_must_understand(discriminator); + be_global->impl_ << + " if (!value_writer.begin_discriminator(MemberParam(0, " << + (must_understand ? "true" : "false") << "))) {\n" + " return false;\n" + " }\n"; + generate_write(value_prefix + "_d()", "disc", discriminator, "i", 1, nested(filter_kind)); + be_global->impl_ << + " if (!value_writer.end_discriminator()) {\n" + " return false;\n" + " }\n"; + } + + if (filter_kind == FieldFilter_All) { + generateSwitchForUnion(u, "value._d()", branch_helper, branches, + discriminator, "", "", type_name.c_str(), + false, false); + } + + be_global->impl_ << + " return value_writer.end_union();\n"; + return true; + } } bool value_writer_generator::gen_enum(AST_Enum*, @@ -277,7 +381,7 @@ bool value_writer_generator::gen_typedef(AST_Typedef*, bool value_writer_generator::gen_struct(AST_Structure* node, UTL_ScopedName* name, - const std::vector& fields, + const std::vector& /*fields*/, AST_Type::SIZE_TYPE, const char*) { @@ -285,48 +389,22 @@ bool value_writer_generator::gen_struct(AST_Structure* node, const std::string type_name = scoped(name); const bool use_cxx11 = be_global->language_mapping() == BE_GlobalData::LANGMAP_CXX11; - const std::string accessor_suffix = use_cxx11 ? "()" : ""; - - { - NamespaceGuard guard; + const ExtensibilityKind ek = be_global->extensibility(node); - Function write("vwrite", "bool"); - write.addArg("value_writer", "OpenDDS::DCPS::ValueWriter&"); - write.addArg("value", "const " + type_name + "&"); - write.endArgs(); + NamespaceGuard guard; + if (!gen_struct_i(node, type_name, use_cxx11, ek, FieldFilter_All) || + !gen_struct_i(node, type_name, use_cxx11, ek, FieldFilter_NestedKeyOnly)) { + return false; + } - const ExtensibilityKind ek = be_global->extensibility(node); - be_global->impl_ << - " if (!value_writer.begin_struct(" << extensibility_kind(ek) << ")) {\n" - " return false;\n" - " }\n"; - for (std::vector::const_iterator pos = fields.begin(), limit = fields.end(); - pos != limit; ++pos) { - AST_Field* const field = *pos; - const std::string field_name = field->local_name()->get_string(); - const std::string idl_name = canonical_name(field); - // TODO: Update the arguments when @optional is available. - const OpenDDS::XTypes::MemberId id = be_global->get_id(field); - const bool must_understand = be_global->is_effectively_must_understand(field); - be_global->impl_ << - " if (!value_writer.begin_struct_member(MemberParam(" << id << ", " << - (must_understand ? "true" : "false") << ", \"" << idl_name << "\", false, true))) {\n" - " return false;\n" - " }\n"; - generate_write("value." + field_name + accessor_suffix, field->field_type(), "i"); - be_global->impl_ << - " if (!value_writer.end_struct_member()) {\n" - " return false;\n" - " }\n"; + if (be_global->is_topic_type(node)) { + if (!gen_struct_i(node, type_name, use_cxx11, ek, FieldFilter_KeyOnly)) { + return false; } - be_global->impl_ << - " return value_writer.end_struct();\n"; } - return true; } - bool value_writer_generator::gen_union(AST_Union* u, UTL_ScopedName* name, const std::vector& branches, @@ -336,38 +414,18 @@ bool value_writer_generator::gen_union(AST_Union* u, be_global->add_include("dds/DCPS/ValueWriter.h", BE_GlobalData::STREAM_H); const std::string type_name = scoped(name); + const ExtensibilityKind ek = be_global->extensibility(u); - { - NamespaceGuard guard; - - Function write("vwrite", "bool"); - write.addArg("value_writer", "OpenDDS::DCPS::ValueWriter&"); - write.addArg("value", "const " + type_name + "&"); - write.endArgs(); - - const ExtensibilityKind ek = be_global->extensibility(u); - be_global->impl_ << - " if (!value_writer.begin_union(" << extensibility_kind(ek) << ")) {\n" - " return false;\n" - " }\n"; - const bool must_understand = be_global->is_effectively_must_understand(discriminator); - be_global->impl_ << - " if (!value_writer.begin_discriminator(MemberParam(0, " << - (must_understand ? "true" : "false") << "))) {\n" - " return false;\n" - " }\n"; - generate_write("value._d()" , discriminator, "i"); - be_global->impl_ << - " if (!value_writer.end_discriminator()) {\n" - " return false;\n" - " }\n"; - - generateSwitchForUnion(u, "value._d()", branch_helper, branches, - discriminator, "", "", type_name.c_str(), - false, false); - be_global->impl_ << - " return value_writer.end_union();\n"; + NamespaceGuard guard; + if (!gen_union_i(u, type_name, branches, discriminator, ek, FieldFilter_All) || + !gen_union_i(u, type_name, branches, discriminator, ek, FieldFilter_NestedKeyOnly)) { + return false; } + if (be_global->is_topic_type(u)) { + if (!gen_union_i(u, type_name, branches, discriminator, ek, FieldFilter_KeyOnly)) { + return false; + } + } return true; } diff --git a/docs/news.d/cmake-xerces.rst b/docs/news.d/cmake-xerces.rst new file mode 100644 index 00000000000..3b2cf84f370 --- /dev/null +++ b/docs/news.d/cmake-xerces.rst @@ -0,0 +1,7 @@ +.. news-prs: 4572 + +.. news-start-section: Platform Support and Dependencies +.. news-start-section: Building with CMake +- Fixed :ghissue:`ACE/TAO build not getting Xerces path <4375>` when using :cmake:var:`OPENDDS_XERCES3`. +.. news-end-section +.. news-end-section diff --git a/docs/news.d/keyonly_vread_vwrite.rst b/docs/news.d/keyonly_vread_vwrite.rst new file mode 100644 index 00000000000..774438d6ede --- /dev/null +++ b/docs/news.d/keyonly_vread_vwrite.rst @@ -0,0 +1,5 @@ +.. news-prs: 4554 + +.. news-start-section: Fixes +- XCDR2 KeyOnly serialization of union that has no key now has a delimiter for appendable and mutable extensibility. +.. news-end-section diff --git a/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.cpp b/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.cpp index d6b11d4b7dc..df1c1631ece 100644 --- a/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.cpp +++ b/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.cpp @@ -294,6 +294,181 @@ TEST(VreadVwriteTest, StaticSerializeTest) //std::cout << output << std::endl; } +template +void write_helper(const T& sample, CORBA::String_out out) +{ + OpenDDS::DCPS::KeyOnly keyonly(sample); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + OpenDDS::DCPS::JsonValueWriter > jvw(writer); + + ASSERT_TRUE(vwrite(jvw, keyonly)); + out = buffer.GetString(); +} + +TEST(VreadVwriteTest, KeyOnly_StructWithNoKeys) +{ + Mod::NoExplicitKeysStruct sample; + OpenDDS::DCPS::set_default(sample); + + // Write the KeyOnly sample to JSON. Then parse the result and compare with the original sample. + // In this case no fields are serialized. + CORBA::String_var result; + write_helper(sample, result); + rapidjson::Document document; + document.Parse(result.in()); + rapidjson::Value& val = document; + + ASSERT_TRUE(val.IsObject()); + ASSERT_TRUE(val.ObjectEmpty()); + + // Read from the JSON result with vread + rapidjson::StringStream buffer(result.in()); + OpenDDS::DCPS::JsonValueReader<> jvr(buffer); + Mod::NoExplicitKeysStruct sample_out; + OpenDDS::DCPS::set_default(sample_out); + const OpenDDS::DCPS::KeyOnly keyonly_out(sample_out); + ASSERT_TRUE(vread(jvr, keyonly_out)); + ASSERT_EQ(sample.b, sample_out.b); + ASSERT_EQ(sample.c, sample_out.c); + ASSERT_EQ(sample.l, sample_out.l); +} + +TEST(VreadVwriteTest, KeyOnly_StructWithKeys) +{ + Mod::KeyOnlyStruct sample; + OpenDDS::DCPS::set_default(sample); + sample.id = 1; + sample.eks.s = 10; + sample.eks.str = "eks.str"; + sample.neks.b = true; + sample.neks.c = 'a'; + sample.neks.l = 12l; + sample.eksarr[0][0].s = 1; + sample.eksarr[0][0].str = "eksarr[0][0].str"; + sample.eksarr[0][1].s = 2; + sample.eksarr[0][1].str = "eksarr[0][1].str"; + sample.eksarr[1][0].s = 3; + sample.eksarr[1][0].str = "eksarr[1][0].str"; + sample.eksarr[1][1].s = 4; + sample.eksarr[1][1].str = "eksarr[1][1].str"; + sample.eku.c('d'); + sample.neku.b(false); + sample.str = "hello"; + + // Write the KeyOnly sample to JSON. Then parse and check the result against the input. + CORBA::String_var result; + write_helper(sample, result); + rapidjson::Document document; + document.Parse(result.in()); + rapidjson::Value& val = document; + + ASSERT_TRUE(val.IsObject()); + ASSERT_EQ(7ul, val.MemberCount()); + ASSERT_EQ(val["id"], 1); + ASSERT_EQ(2ul, val["eks"].MemberCount()); + ASSERT_EQ(val["eks"]["s"], 10); + ASSERT_EQ(val["eks"]["str"], "eks.str"); + ASSERT_EQ(val["neks"]["b"], true); + ASSERT_EQ(val["neks"]["c"], "a"); + ASSERT_EQ(val["neks"]["l"], 12); + ASSERT_EQ(2ul, val["eksarr"].Size()); + ASSERT_EQ(2ul, val["eksarr"][0].Size()); + ASSERT_EQ(2ul, val["eksarr"][1].Size()); + ASSERT_EQ(2ul, val["eksarr"][0][0].MemberCount()); + ASSERT_EQ(val["eksarr"][0][0]["s"], 1); + ASSERT_EQ(val["eksarr"][0][0]["str"], "eksarr[0][0].str"); + ASSERT_EQ(2ul, val["eksarr"][0][1].MemberCount()); + ASSERT_EQ(val["eksarr"][0][1]["s"], 2); + ASSERT_EQ(val["eksarr"][0][1]["str"], "eksarr[0][1].str"); + ASSERT_EQ(2ul, val["eksarr"][1][0].MemberCount()); + ASSERT_EQ(val["eksarr"][1][0]["s"], 3); + ASSERT_EQ(val["eksarr"][1][0]["str"], "eksarr[1][0].str"); + ASSERT_EQ(2ul, val["eksarr"][1][1].MemberCount()); + ASSERT_EQ(val["eksarr"][1][1]["s"], 4); + ASSERT_EQ(val["eksarr"][1][1]["str"], "eksarr[1][1].str"); + ASSERT_EQ(1ul, val["eku"].MemberCount()); + ASSERT_EQ(val["eku"]["$discriminator"], "two"); + ASSERT_EQ(1ul, val["neku"].MemberCount()); + ASSERT_EQ(val["neku"]["$discriminator"], "one"); + ASSERT_EQ(val["str"], "hello"); + + // Read from the JSON result into a KeyOnly sample and compare with the original sample. + rapidjson::StringStream buffer(result.in()); + OpenDDS::DCPS::JsonValueReader<> jvr(buffer); + Mod::KeyOnlyStruct sample_out; + OpenDDS::DCPS::set_default(sample_out); + const OpenDDS::DCPS::KeyOnly keyonly_out(sample_out); + + ASSERT_TRUE(vread(jvr, keyonly_out)); + ASSERT_EQ(sample.id, sample_out.id); + ASSERT_EQ(sample.eks.s, sample_out.eks.s); + ASSERT_STREQ(sample.eks.str, sample_out.eks.str); + ASSERT_EQ(sample.neks.b, sample_out.neks.b); + ASSERT_EQ(sample.neks.c, sample_out.neks.c); + ASSERT_EQ(sample.neks.l, sample_out.neks.l); + ASSERT_EQ(sample.eksarr[0][0].s, sample_out.eksarr[0][0].s); + ASSERT_STREQ(sample.eksarr[0][0].str, sample_out.eksarr[0][0].str); + ASSERT_EQ(sample.eksarr[0][1].s, sample_out.eksarr[0][1].s); + ASSERT_STREQ(sample.eksarr[0][1].str, sample_out.eksarr[0][1].str); + ASSERT_EQ(sample.eksarr[1][0].s, sample_out.eksarr[1][0].s); + ASSERT_STREQ(sample.eksarr[1][0].str, sample_out.eksarr[1][0].str); + ASSERT_EQ(sample.eksarr[1][1].s, sample_out.eksarr[1][1].s); + ASSERT_STREQ(sample.eksarr[1][1].str, sample_out.eksarr[1][1].str); + ASSERT_EQ(sample.eku._d(), sample_out.eku._d()); + ASSERT_EQ(sample.neku._d(), sample_out.neku._d()); + ASSERT_STREQ(sample.str, sample_out.str); +} + +TEST(VreadVwriteTest, KeyOnly_UnionWithNoKey) +{ + Mod::NoExplicitKeyUnion sample; + OpenDDS::DCPS::set_default(sample); + + CORBA::String_var result; + write_helper(sample, result); + rapidjson::Document document; + document.Parse(result.in()); + rapidjson::Value& val = document; + + ASSERT_TRUE(val.IsObject()); + ASSERT_TRUE(val.ObjectEmpty()); + + rapidjson::StringStream buffer(result.in()); + OpenDDS::DCPS::JsonValueReader<> jvr(buffer); + Mod::NoExplicitKeyUnion sample_out; + OpenDDS::DCPS::set_default(sample_out); + const OpenDDS::DCPS::KeyOnly keyonly_out(sample_out); + ASSERT_TRUE(vread(jvr, keyonly_out)); + ASSERT_EQ(sample._d(), sample_out._d()); +} + +TEST(VreadVwriteTest, KeyOnly_UnionWithKey) +{ + Mod::ExplicitKeyUnion sample; + sample.o(0x22); + sample._d(Mod::three); + + CORBA::String_var result; + write_helper(sample, result); + rapidjson::Document document; + document.Parse(result.in()); + rapidjson::Value& val = document; + + ASSERT_TRUE(val.IsObject()); + ASSERT_EQ(1ul, val.MemberCount()); + ASSERT_EQ(val["$discriminator"], "three"); + + rapidjson::StringStream buffer(result.in()); + OpenDDS::DCPS::JsonValueReader<> jvr(buffer); + Mod::ExplicitKeyUnion sample_out; + OpenDDS::DCPS::set_default(sample_out); + const OpenDDS::DCPS::KeyOnly keyonly_out(sample_out); + ASSERT_TRUE(vread(jvr, keyonly_out)); + ASSERT_EQ(sample._d(), sample_out._d()); +} + #ifndef OPENDDS_SAFETY_PROFILE DDS::DynamicType_var get_dynamic_type(OpenDDS::XTypes::TypeLookupService& tls) diff --git a/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.idl b/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.idl index 7eb2dd5fd71..56f647d0549 100644 --- a/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.idl +++ b/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.idl @@ -95,4 +95,52 @@ module Mod { MaskType mask; }; + /////// For KeyOnly tests + struct ExplicitKeysStruct { + @key short s; + @key string str; + unsigned long long ull; + }; + + typedef ExplicitKeysStruct ExplicitKeysStructArr[2][2]; + + @topic + struct NoExplicitKeysStruct { + boolean b; + char c; + long l; + }; + +#define COMMON_BRANCHES \ + case one: \ + boolean b; \ + case two: \ + char c; \ + default: \ + octet o; \ + + @topic + union ExplicitKeyUnion switch (@key MyEnum) { + COMMON_BRANCHES + }; + + @topic + union NoExplicitKeyUnion switch (MyEnum) { + COMMON_BRANCHES + }; + + @topic + struct KeyOnlyStruct { + @key long id; + @key ExplicitKeysStruct eks; + @key NoExplicitKeysStruct neks; + @key ExplicitKeysStructArr eksarr; + @key ExplicitKeyUnion eku; + @key NoExplicitKeyUnion neku; + @key string str; + octet o; + MaskedJunk mj; + long long ll; + }; + }; diff --git a/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.mpc b/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.mpc index f76607e36e5..f595046dce5 100644 --- a/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.mpc +++ b/tests/DCPS/Compiler/vread_vwrite/VreadVwriteTest.mpc @@ -1,4 +1,4 @@ -project: dcpsexe, dcps_test, googletest, rapidjson, opendds_uses_cxx11 { +project: dcpsexe, dcps_test, googletest, rapidjson, opendds_uses_cxx11, msvc_bigobj { dcps_ts_flags += -Gxtypes-complete exename = * diff --git a/tests/DCPS/Compiler/xcdr/xcdr.cpp b/tests/DCPS/Compiler/xcdr/xcdr.cpp index 8a58364977b..e40f4753dbd 100644 --- a/tests/DCPS/Compiler/xcdr/xcdr.cpp +++ b/tests/DCPS/Compiler/xcdr/xcdr.cpp @@ -309,8 +309,11 @@ template void baseline_checks_vwrite(const Encoding& encoding, const Type& value, const DataView& expected_cdr) { if (encoding.kind() == Encoding::KIND_XCDR2) { + // Compute serialized size Xcdr2ValueWriter value_writer(encoding); - vwrite(value_writer, value); + EXPECT_TRUE(vwrite(value_writer, value)); + + // Serialize ACE_Message_Block buffer(value_writer.get_serialized_size()); Serializer ser(&buffer, encoding); value_writer.set_serializer(&ser); @@ -2000,6 +2003,16 @@ void key_only_test(bool topic_type) amalgam_serializer_test_base( xcdr2, expected, wrapped_value, wrapped_result, field_filter); EXPECT_PRED_FORMAT2(assert_values, wrapped_value, wrapped_result); + + // Test vwrite with KeyOnly or NestedKeyOnly samples + Xcdr2ValueWriter value_writer(xcdr2); + EXPECT_TRUE(vwrite(value_writer, wrapped_value)); + + ACE_Message_Block buffer(value_writer.get_serialized_size()); + Serializer ser(&buffer, xcdr2); + value_writer.set_serializer(&ser); + EXPECT_TRUE(vwrite(value_writer, wrapped_value)); + EXPECT_PRED_FORMAT2(assert_DataView, expected, buffer); } void serialize_u32(DataVec& data_vec, size_t value) @@ -2140,55 +2153,57 @@ void key_only_complex_set_base_values(Type& value, const bool include_possible_keyed = (field_filter != FieldFilter_KeyOnly) || keyed; const bool include_unkeyed = field_filter == FieldFilter_All || (!keyed && field_filter == FieldFilter_NestedKeyOnly); + const FieldFilter nested_field_filter = + field_filter == FieldFilter_All ? FieldFilter_All : FieldFilter_NestedKeyOnly; set_default(value); if (include_possible_keyed) { key_only_set_base_values( - value.unkeyed_struct_value, field_filter, false); + value.unkeyed_struct_value, nested_field_filter, false); key_only_set_base_values( - value.unkeyed_struct_array_value[0], field_filter, false); + value.unkeyed_struct_array_value[0], nested_field_filter, false); key_only_set_base_values( - value.unkeyed_struct_array_value[1], field_filter, false); + value.unkeyed_struct_array_value[1], nested_field_filter, false); /* TODO(iguessthislldo): See IDL Def value.unkeyed_struct_seq_value.length(1); key_only_set_base_values( - value.unkeyed_struct_seq_value[0], field_filter, false); + value.unkeyed_struct_seq_value[0], nested_field_filter, false); */ key_only_set_base_values( - value.keyed_struct_value, field_filter, true); + value.keyed_struct_value, nested_field_filter, true); key_only_set_base_values( - value.keyed_struct_array_value[0], field_filter, true); + value.keyed_struct_array_value[0], nested_field_filter, true); key_only_set_base_values( - value.keyed_struct_array_value[1], field_filter, true); + value.keyed_struct_array_value[1], nested_field_filter, true); /* TODO(iguessthislldo): See IDL Def value.keyed_struct_seq_value.length(1); key_only_set_base_values( - value.keyed_struct_seq_value[0], field_filter, true); + value.keyed_struct_seq_value[0], nested_field_filter, true); */ key_only_union_set_base_values( - value.unkeyed_union_value, field_filter, false); + value.unkeyed_union_value, nested_field_filter, false); key_only_union_set_base_values( - value.unkeyed_union_array_value[0], field_filter, false); + value.unkeyed_union_array_value[0], nested_field_filter, false); key_only_union_set_base_values( - value.unkeyed_union_array_value[1], field_filter, false); + value.unkeyed_union_array_value[1], nested_field_filter, false); /* TODO(iguessthislldo): See IDL Def value.unkeyed_union_seq_value.length(1); key_only_union_set_base_values( - value.unkeyed_union_seq_value[0], field_filter, false); + value.unkeyed_union_seq_value[0], nested_field_filter, false); */ key_only_union_set_base_values( - value.keyed_union_value, field_filter, true); + value.keyed_union_value, nested_field_filter, true); key_only_union_set_base_values( - value.keyed_union_array_value[0], field_filter, true); + value.keyed_union_array_value[0], nested_field_filter, true); key_only_union_set_base_values( - value.keyed_union_array_value[1], field_filter, true); + value.keyed_union_array_value[1], nested_field_filter, true); /* TODO(iguessthislldo): See IDL Def value.keyed_union_seq_value.length(1); key_only_union_set_base_values( - value.keyed_union_seq_value[0], field_filter, true); + value.keyed_union_seq_value[0], nested_field_filter, true); */ } @@ -2533,9 +2548,7 @@ void build_expected_union(DataVec& expected, FieldFilter field_filter, bool keye if (include_unkeyed) { non_keys = DataView(key_only_union_non_keys_expected_base); } - if (include_possible_keyed) { - serialize_u32(expected, keys.size + non_keys.size); - } + serialize_u32(expected, keys.size + non_keys.size); keys.copy_to(expected); non_keys.copy_to(expected); } @@ -2562,7 +2575,7 @@ void build_expected_complex_struct(DataVec& expected, FieldFilter field_filter, field_filter == FieldFilter_All ? FieldFilter_All : FieldFilter_NestedKeyOnly; if (include_possible_keyed) { - build_expected_basic_struct(all_contents, field_filter, false); + build_expected_basic_struct(all_contents, nested_field_filter, false); { DataVec array_contents; build_expected_basic_struct(array_contents, nested_field_filter, false); @@ -2713,6 +2726,18 @@ TEST(KeyTests, KeyOnly_KeyedUnion) KeyOnly, KeyOnly >(true); } +TEST(KeyTests, KeyOnly_ComplexUnkeyedStruct) +{ + key_only_test, KeyOnly >(true); +} + +TEST(KeyTests, KeyOnly_ComplexKeyedStruct) +{ + key_only_test, KeyOnly >(true); +} + // ---------------------------------------------------------------------------- int main(int argc, char* argv[]) diff --git a/tools/dds/rtpsrelaylib/CMakeLists.txt b/tools/dds/rtpsrelaylib/CMakeLists.txt index 9f3a1925bf6..2561ccc9c79 100644 --- a/tools/dds/rtpsrelaylib/CMakeLists.txt +++ b/tools/dds/rtpsrelaylib/CMakeLists.txt @@ -18,7 +18,7 @@ target_sources(OpenDDS_RtpsRelayLib Utility.h export.h ) -_opendds_library(OpenDDS_RtpsRelayLib) +_opendds_library(OpenDDS_RtpsRelayLib MSVC_BIGOBJ) target_link_libraries(OpenDDS_RtpsRelayLib PUBLIC ${deps}) opendds_target_sources(OpenDDS_RtpsRelayLib