diff --git a/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/cdr_stream.hpp b/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/cdr_stream.hpp index 86302b19..865f60e6 100644 --- a/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/cdr_stream.hpp +++ b/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/cdr_stream.hpp @@ -432,6 +432,21 @@ class OMG_DDS_API cdr_stream { */ virtual bool finish_member(const entity_properties_t &props, member_id_set &member_ids, bool is_set = true); + /** + * @brief + * Function declaration for finishing an existing member. + * + * This function is called by next_entity for each entity which is iterated over. + * Depending on the implementation and mode header length fields may be completed. + * This function can be overridden in cdr streaming implementations. + * + * @param[in] props Properties of the member to finish. + * @param[in] is_set Whether the entity represented by prop is present, if it is an optional entity. + * + * @return Whether the operation was completed succesfully. + */ + virtual bool finish_member_unchecked(const entity_properties_t &props, bool is_set = true); + /** * @brief * Function declaration for retrieving the next entity to be operated on by the streamer. @@ -481,7 +496,20 @@ class OMG_DDS_API cdr_stream { * * @return Whether the struct is complete and correct. */ - virtual bool finish_struct(const entity_properties_t &props, const member_id_set &member_ids); + virtual bool finish_struct(const entity_properties_t &props, const member_id_set &member_ids) {return check_struct_completeness(props, member_ids);} + + /** + * @brief + * Function declaration for finishing a parameter list. + * + * This function is called by the generated functions for the entity, and will trigger the necessary actions on finishing the current struct. + * I.E. finishing headers, writing length fields. + * + * @param[in] props The entity whose members might be represented by a parameter list. + * + * @return Whether the struct is complete and correct. + */ + virtual bool finish_struct_unchecked(const entity_properties_t &props) {(void)props; return true;} /** * @brief @@ -941,6 +969,39 @@ bool max_string(S& str, const T& max_sz, size_t N) return true; } +/** + * @brief + * Sequence of base types read function. + * + * This is called when a resize + memcpy is way less efficient than an assign, + * as this skips the default initialization of entities in the sequence. + * + * @param[in, out] str The stream being read from. + * @param[in] toread The sequence being read into. + * @param[in] N Number of base entities to read. + * + * @return Whether the operation was completed succesfully. + */ +template class V, typename T, typename A, std::enable_if_t::value && std::is_arithmetic::value && !std::is_same::value, bool> = true > +bool read(S& str, V &toread, size_t N) +{ + if (str.position() == SIZE_MAX + || !str.align(sizeof(T), false) + || !str.bytes_available(sizeof(T)*N)) + return false; + + auto ptr = reinterpret_cast(str.get_cursor()); + toread.assign(ptr, ptr+N); + str.incr_position(N*sizeof(T)); + + if (str.swap_endianness()) { + for (auto &e:toread) + byte_swap(&e); + } + + return true; +} + } } } diff --git a/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/extended_cdr_v1_ser.hpp b/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/extended_cdr_v1_ser.hpp index 87d8283a..96916954 100644 --- a/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/extended_cdr_v1_ser.hpp +++ b/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/extended_cdr_v1_ser.hpp @@ -59,12 +59,11 @@ class OMG_DDS_API xcdr_v1_stream : public cdr_stream { * Determines whether a header is necessary for this entity through header_necessary, and if it is, completes the previous header. * * @param[in] prop Properties of the member to finish. - * @param[in] member_ids Container for the member ids of members succesfully streamed at this level * @param[in] is_set Whether the entity represented by prop is present, if it is an optional entity. * * @return Whether the operation was completed succesfully. */ - bool finish_member(const entity_properties_t &prop, member_id_set &member_ids, bool is_set = true); + bool finish_member_unchecked(const entity_properties_t &prop, bool is_set = true); /** * @brief @@ -99,11 +98,10 @@ class OMG_DDS_API xcdr_v1_stream : public cdr_stream { * Adds the final parameter list entry if necessary when writing to the stream. * * @param[in] props The property tree to get the next entity from. - * @param[in] member_ids Container for the member ids of members succesfully streamed at this level * * @return Whether the struct is complete and correct. */ - bool finish_struct(const entity_properties_t &props, const member_id_set &member_ids); + bool finish_struct_unchecked(const entity_properties_t &props); private: diff --git a/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/extended_cdr_v2_ser.hpp b/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/extended_cdr_v2_ser.hpp index 34298195..511d400c 100644 --- a/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/extended_cdr_v2_ser.hpp +++ b/src/ddscxx/include/org/eclipse/cyclonedds/core/cdr/extended_cdr_v2_ser.hpp @@ -65,12 +65,11 @@ class OMG_DDS_API xcdr_v2_stream : public cdr_stream { * Determines whether a header is necessary for this entity through em_header_necessary, and if it is, completes the previous header. * * @param[in] prop Properties of the member to finish. - * @param[in] member_ids Container for the member ids of members succesfully streamed at this level * @param[in] is_set Whether the entity represented by prop is present, if it is an optional entity. * * @return Whether the operation was completed succesfully. */ - bool finish_member(const entity_properties_t &prop, member_id_set &member_ids, bool is_set = true); + bool finish_member_unchecked(const entity_properties_t &prop, bool is_set = true); /** * @brief @@ -123,6 +122,18 @@ class OMG_DDS_API xcdr_v2_stream : public cdr_stream { */ bool finish_struct(const entity_properties_t &props, const member_id_set &member_ids); + /** + * @brief + * Finish the current struct. + * + * This function is called by the generated streaming functions, and will finish the current parameter list, if that is relevant for it. + * + * @param[in] props The entity whose members might be represented by a parameter list. + * + * @return Whether the struct is complete and correct. + */ + bool finish_struct_unchecked(const entity_properties_t &props); + /** * @brief * Function declaration for starting an array or sequence of non-primitive types. diff --git a/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/cdr_stream.cpp b/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/cdr_stream.cpp index 1d673c16..ad4e42bc 100644 --- a/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/cdr_stream.cpp +++ b/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/cdr_stream.cpp @@ -53,17 +53,6 @@ bool cdr_stream::align(size_t newalignment, bool add_zeroes) return true; } -bool cdr_stream::finish_struct(const entity_properties_t &props, const member_id_set &member_ids) -{ - switch (m_mode) { - case stream_mode::read: - return check_struct_completeness(props, member_ids); - break; - default: - return true; - } -} - const entity_properties_t *cdr_stream::first_entity(const entity_properties_t *props) { const entity_properties_t *prop = props->first_member; @@ -140,11 +129,19 @@ bool cdr_stream::check_struct_completeness(const entity_properties_t &props, con bool cdr_stream::finish_member(const entity_properties_t &props, member_id_set &member_ids, bool is_set) { + if (!finish_member_unchecked(props, is_set)) + return false; + if (is_set) member_ids.insert(props.m_id); return true; } +bool cdr_stream::finish_member_unchecked(const entity_properties_t &, bool) +{ + return true; +} + } } } diff --git a/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/extended_cdr_v1_ser.cpp b/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/extended_cdr_v1_ser.cpp index c34032a1..e18325e1 100644 --- a/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/extended_cdr_v1_ser.cpp +++ b/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/extended_cdr_v1_ser.cpp @@ -55,7 +55,7 @@ bool xcdr_v1_stream::start_member(const entity_properties_t &prop, bool is_set) return cdr_stream::start_member(prop, is_set); } -bool xcdr_v1_stream::finish_member(const entity_properties_t &prop, member_id_set &member_ids, bool is_set) +bool xcdr_v1_stream::finish_member_unchecked(const entity_properties_t &prop, bool is_set) { if (header_necessary(prop)) { switch (m_mode) { @@ -73,7 +73,7 @@ bool xcdr_v1_stream::finish_member(const entity_properties_t &prop, member_id_se } pop_member_start(); - return cdr_stream::finish_member(prop, member_ids, is_set); + return cdr_stream::finish_member_unchecked(prop, is_set); } const entity_properties_t* xcdr_v1_stream::next_entity(const entity_properties_t *prop) @@ -288,7 +288,7 @@ bool xcdr_v1_stream::finish_write_header(const entity_properties_t &props) return true; } -bool xcdr_v1_stream::finish_struct(const entity_properties_t &props, const member_id_set &member_ids) +bool xcdr_v1_stream::finish_struct_unchecked(const entity_properties_t &props) { switch (m_mode) { case stream_mode::write: @@ -300,11 +300,8 @@ bool xcdr_v1_stream::finish_struct(const entity_properties_t &props, const membe if (list_necessary(props)) return move_final_list_entry(); break; - case stream_mode::read: - return check_struct_completeness(props, member_ids); - break; default: - return false; + break; } return true; } diff --git a/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/extended_cdr_v2_ser.cpp b/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/extended_cdr_v2_ser.cpp index 31eac17b..9044a8df 100644 --- a/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/extended_cdr_v2_ser.cpp +++ b/src/ddscxx/src/org/eclipse/cyclonedds/core/cdr/extended_cdr_v2_ser.cpp @@ -64,7 +64,7 @@ bool xcdr_v2_stream::start_member(const entity_properties_t &prop, bool is_set) return cdr_stream::start_member(prop, is_set); } -bool xcdr_v2_stream::finish_member(const entity_properties_t &prop, member_id_set &member_ids, bool is_set) +bool xcdr_v2_stream::finish_member_unchecked(const entity_properties_t &prop, bool is_set) { switch (m_mode) { case stream_mode::write: @@ -83,7 +83,7 @@ bool xcdr_v2_stream::finish_member(const entity_properties_t &prop, member_id_se m_consecutives.pop(); pop_member_start(); - return cdr_stream::finish_member(prop, member_ids, is_set); + return cdr_stream::finish_member_unchecked(prop, is_set); } bool xcdr_v2_stream::write_d_header() @@ -313,21 +313,19 @@ bool xcdr_v2_stream::start_struct(const entity_properties_t &props) bool xcdr_v2_stream::finish_struct(const entity_properties_t &props, const member_id_set &member_ids) { - switch (m_mode) { - case stream_mode::write: - if (d_header_necessary(props) && !finish_d_header()) - return false; - break; - case stream_mode::read: - if (!check_struct_completeness(props, member_ids)) - return false; - else if (d_header_necessary(props)) - m_buffer_end.pop(); - break; - default: - break; - } + if (!cdr_stream::finish_struct(props, member_ids)) + return false; + else if (d_header_necessary(props)) + m_buffer_end.pop(); + + return true; +} +bool xcdr_v2_stream::finish_struct_unchecked(const entity_properties_t &props) +{ + if (stream_mode::write == m_mode && d_header_necessary(props) && !finish_d_header()) + return false; + return true; } diff --git a/src/idlcxx/src/streamers.c b/src/idlcxx/src/streamers.c index e86e878b..62c430cf 100644 --- a/src/idlcxx/src/streamers.c +++ b/src/idlcxx/src/streamers.c @@ -365,7 +365,8 @@ write_base_type_streaming_functions( const idl_type_spec_t* type_spec, const char* accessor, const char* read_accessor, - instance_location_t loc) + instance_location_t loc, + bool skip_reads) { const char* fmt = " if (!{T}(streamer, %1$s))\n" @@ -390,7 +391,7 @@ write_base_type_streaming_functions( } if (multi_putf(streams, CONST, fmt, accessor) - || multi_putf(streams, READ, rfmt, read_accessor)) + || (!skip_reads && multi_putf(streams, READ, rfmt, read_accessor))) return IDL_RETCODE_NO_MEMORY; return IDL_RETCODE_OK; @@ -402,24 +403,25 @@ write_streaming_functions( const idl_type_spec_t* type_spec, const char* accessor, const char* read_accessor, - instance_location_t loc) + instance_location_t loc, + bool skip_reads) { if (idl_is_alias(type_spec)) { const idl_typedef_t *td = idl_parent(type_spec); const idl_type_spec_t *ts = idl_type_spec(td); //if this is an alias for a bare type, just use the bare type if (!idl_is_array(td->declarators) && !idl_is_sequence(ts) && (idl_is_base_type(ts) || idl_is_string(ts))) - return write_streaming_functions(streams, ts, accessor, read_accessor, loc); + return write_streaming_functions(streams, ts, accessor, read_accessor, loc, skip_reads); else return write_typedef_streaming_functions(streams, type_spec, accessor, read_accessor); } else if (idl_is_forward(type_spec)) { - return write_streaming_functions(streams, idl_type_spec(type_spec), accessor, read_accessor, loc); + return write_streaming_functions(streams, idl_type_spec(type_spec), accessor, read_accessor, loc, skip_reads); } else if (idl_is_string(type_spec)) { return write_string_streaming_functions(streams, type_spec, accessor, read_accessor); } else if (idl_is_union(type_spec) || idl_is_struct(type_spec)) { return write_constructed_type_streaming_functions(streams, accessor, read_accessor); } else { - return write_base_type_streaming_functions(streams, type_spec, accessor, read_accessor, loc); + return write_base_type_streaming_functions(streams, type_spec, accessor, read_accessor, loc, skip_reads); } } @@ -439,7 +441,8 @@ sequence_writes(const idl_pstate_t* pstate, size_t depth, const char* accessor, const char* read_accessor, - instance_location_t loc) + instance_location_t loc, + bool skip_reads) { const idl_type_spec_t *type_spec = seq->type_spec; @@ -457,7 +460,7 @@ sequence_writes(const idl_pstate_t* pstate, if (IDL_PRINTA(&type, get_cpp11_type, type_spec, streams->generator) < 0 || multi_putf(streams, MOVE | MAX, mfmt, type, depth) || multi_putf(streams, WRITE, sfmt, accessor, depth) - || multi_putf(streams, READ, sfmt, read_accessor, depth)) + || (!skip_reads && multi_putf(streams, READ, sfmt, read_accessor, depth))) return IDL_RETCODE_NO_MEMORY; return IDL_RETCODE_OK; @@ -483,7 +486,7 @@ sequence_writes(const idl_pstate_t* pstate, if (unroll_sequence (pstate, streams, (idl_sequence_t*)type_spec, depth + 1, new_accessor, new_read_accessor, loc)) return IDL_RETCODE_NO_MEMORY; } else { - if (write_streaming_functions (streams, type_spec, new_accessor, new_read_accessor, loc)) + if (write_streaming_functions (streams, type_spec, new_accessor, new_read_accessor, loc, skip_reads)) return IDL_RETCODE_NO_MEMORY; } @@ -513,7 +516,7 @@ unroll_sequence(const idl_pstate_t* pstate, " return false;\n"; static const char* fmt1 = " {\n" - " uint32_t se_%1$u = uint32_t(%2$s.size());\n"; + " uint32_t se_%1$u(static_cast(%2$s.size()));\n"; static const char* length_check = " if (se_%1$u > %2$u &&\n" " streamer.status(serialization_status::{T}_bound_exceeded))\n" @@ -523,23 +526,35 @@ unroll_sequence(const idl_pstate_t* pstate, " return false;\n"; static const char* rfmt = " %1$s.resize(se_%2$u);\n"; + static const char* rfmt2 = + " if (!read(streamer,%1$s,se_%2$u))\n" + " return false;\n"; static const char* mfmt = " {\n" " uint32_t se_%1$u = %2$u;\n"; + static const char* rfmt3 = + " {\n" + " uint32_t se_%1$u(0);\n"; const idl_type_spec_t *root_type_spec = idl_strip(seq->type_spec, IDL_STRIP_ALIASES | IDL_STRIP_FORWARD); if (multi_putf(streams, ALL, consec_start_fmt, idl_is_base_type(root_type_spec) && !idl_is_array(root_type_spec) ? "true" : "false")) return IDL_RETCODE_NO_MEMORY; - if (multi_putf(streams, READ, fmt1, depth, read_accessor) + bool skip_reads = !idl_is_sequence(seq->type_spec) && idl_is_base_type(root_type_spec) && !(idl_mask(root_type_spec) == IDL_BOOL); + + if (multi_putf(streams, READ, rfmt3, depth) || multi_putf(streams, (WRITE | MOVE), fmt1, depth, accessor) || multi_putf(streams, MAX, mfmt, depth, maximum) - || (maximum && multi_putf(streams, NOMAX, length_check, depth, maximum)) || multi_putf(streams, ALL, fmt2, depth) - || multi_putf(streams, READ, rfmt, read_accessor, depth)) + || (maximum && multi_putf(streams, NOMAX, length_check, depth, maximum))) return IDL_RETCODE_NO_MEMORY; - if (sequence_writes(pstate, streams, seq, depth, accessor, read_accessor, loc)) + if (!skip_reads && multi_putf(streams, READ, rfmt, read_accessor, depth)) + return IDL_RETCODE_NO_MEMORY; + else if (skip_reads && multi_putf(streams, READ, rfmt2, read_accessor, depth)) + return IDL_RETCODE_NO_MEMORY; + + if (sequence_writes(pstate, streams, seq, depth, accessor, read_accessor, loc, skip_reads)) return IDL_RETCODE_NO_MEMORY; //close sequence @@ -655,7 +670,7 @@ process_entity( if (unroll_sequence(pstate, streams, (idl_sequence_t*)type_spec, 1, accessor, read_accessor, loc)) return IDL_RETCODE_NO_MEMORY; } else { - if (write_streaming_functions(streams, type_spec, accessor, read_accessor, loc)) + if (write_streaming_functions(streams, type_spec, accessor, read_accessor, loc, false)) return IDL_RETCODE_NO_MEMORY; } @@ -813,17 +828,29 @@ add_member_finish( const idl_declarator_t *decl, struct streams *streams) { + const void *_struct = idl_parent(idl_parent(decl)); + bool is_final = idl_is_extensible(_struct, IDL_FINAL); + if (is_optional(decl)) { instance_location_t loc = {.parent = "instance"}; char *accessor = NULL; if (IDL_PRINTA(&accessor, get_instance_accessor, decl, &loc) < 0 || multi_putf(streams, (WRITE|MOVE), " }\n") - || multi_putf(streams, ALL, - " if (!streamer.finish_member(*prop, member_ids, %1$s.has_value()))\n" + || multi_putf(streams, READ, + " if (!streamer.finish_member%1$s(*prop%2$s, %3$s.has_value()))\n" + " return false;\n", is_final ? "_unchecked" : "", is_final ? "" : ", member_ids", accessor) + || multi_putf(streams, (WRITE|MOVE), + " if (!streamer.finish_member_unchecked(*prop, %1$s.has_value()))\n" + " return false;\n", accessor) + || multi_putf(streams, MAX, + " if (!streamer.finish_member_unchecked(*prop, true))\n" " return false;\n", accessor)) return IDL_RETCODE_NO_MEMORY; } else { - if (multi_putf(streams, ALL, " if (!streamer.finish_member(*prop, member_ids))\n" + if (multi_putf(streams, READ, + " if (!streamer.finish_member%1$s(*prop%2$s))\n" + " return false;\n", is_final ? "_unchecked" : "", is_final ? "" : ", member_ids") + || multi_putf(streams, CONST, " if (!streamer.finish_member_unchecked(*prop))\n" " return false;\n")) return IDL_RETCODE_NO_MEMORY; } @@ -1067,7 +1094,7 @@ print_constructed_type_open(struct streams *streams, const idl_node_t *node) "template::value, bool> = true >\n" "bool {T}(T& streamer, {C}%1$s& instance, const entity_properties_t *props) {\n" " (void)instance;\n" - " member_id_set member_ids;\n"; + "%2$s"; static const char *pfmt1 = "template<>\n" "const propvec &get_type_props<%s>()%s"; @@ -1087,10 +1114,11 @@ print_constructed_type_open(struct streams *streams, const idl_node_t *node) " if (!streamer.start_struct(*props))\n" " return false;\n"; - const char *ext = NULL; + bool is_final = false; switch (get_extensibility(node)) { case IDL_FINAL: + is_final = true; ext = "ext_final"; break; case IDL_APPENDABLE: @@ -1103,7 +1131,8 @@ print_constructed_type_open(struct streams *streams, const idl_node_t *node) assert(0); } - if (multi_putf(streams, ALL, fmt, name) + if (multi_putf(streams, READ, fmt, name, is_final ? "" : " member_id_set member_ids;\n") + || multi_putf(streams, CONST, fmt, name, "") || putf(&streams->props, pfmt1, name, pfmt2) || idl_fprintf(streams->generator->header.handle, pfmt1, name, ";\n\n") < 0 || multi_putf(streams, ALL, sfmt) @@ -1133,7 +1162,7 @@ print_constructed_type_close( const void* node) { const char *fmt = - " return streamer.finish_struct(*props, member_ids);\n" + " return streamer.finish_struct%1$s(*props%2$s);\n" "}\n\n"; static const char *pfmt = "\n entity_properties_t::finish(props, keylist);\n" @@ -1158,7 +1187,9 @@ print_constructed_type_close( ptr++; } - if (multi_putf(streams, ALL, fmt) + bool is_final = idl_is_extensible(node, IDL_FINAL); + if (multi_putf(streams, CONST, fmt, "_unchecked", "") + || multi_putf(streams, READ, fmt, is_final ? "_unchecked" : "", is_final ? "" : ", member_ids") || putf(&streams->props, pfmt) || idl_fprintf(streams->generator->header.handle, pfmt2, newname, fullname) < 0) return IDL_RETCODE_NO_MEMORY; @@ -1384,7 +1415,7 @@ process_typedef_decl( "template::value, bool> = true >\n" "bool {T}_%1$s(T& streamer, {C}%2$s& instance) {\n" " (void)instance;\n" - " member_id_set member_ids;\n"; + "%3$s"; char* name = NULL; if (IDL_PRINTA(&name, get_cpp11_name_typedef, declarator, streams->generator) < 0) return IDL_RETCODE_NO_MEMORY; @@ -1398,7 +1429,8 @@ process_typedef_decl( ts = ((const idl_sequence_t*)ts)->type_spec; } - if (multi_putf(streams, ALL, fmt, name, fullname)) + if (multi_putf(streams, READ, fmt, name, fullname, " member_id_set member_ids;\n") + || multi_putf(streams, CONST, fmt, name, fullname, "")) return IDL_RETCODE_NO_MEMORY; if (!idl_is_base_type(ts) && !idl_is_enum(ts) && !idl_is_string(ts) && !idl_is_alias(ts)) {