Skip to content

Commit

Permalink
Foxy backport of #648 and #650 (#667)
Browse files Browse the repository at this point in the history
* Implement equality operator function for C messages. (#648)

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>

* Implement copy function for C messages (#650)

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>

* Replace rcutils_allocator with the system allocator

Signed-off-by: Nikolai Morin <nnmmgit@gmail.com>

* Set the output size unconditionally when copying sequences

Signed-off-by: Nikolai Morin <nnmmgit@gmail.com>

Co-authored-by: Michel Hidalgo <michel@ekumenlabs.com>
  • Loading branch information
nnmm and hidmic authored Apr 25, 2022
1 parent 19db1aa commit b6e9005
Show file tree
Hide file tree
Showing 12 changed files with 1,037 additions and 23 deletions.
141 changes: 141 additions & 0 deletions rosidl_generator_c/resource/msg__functions.c.em
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,90 @@ for line in lines:
}@
}

bool
@(message_typename)__are_equal(const @(message_typename) * lhs, const @(message_typename) * rhs)
{
if (!lhs || !rhs) {
return false;
}
@[for member in message.structure.members]@
// @(member.name)
@[ if isinstance(member.type, Array)]@
for (size_t i = 0; i < @(member.type.size); ++i) {
@[ if isinstance(member.type.value_type, (AbstractGenericString, NamespacedType))]@
if (!@(basetype_to_c(member.type.value_type))__are_equal(
&(lhs->@(member.name)[i]), &(rhs->@(member.name)[i])))
{
return false;
}
@[ else]@
if (lhs->@(member.name)[i] != rhs->@(member.name)[i]) {
return false;
}
@[ end if]@
}
@[ elif isinstance(member.type, AbstractSequence)]@
if (!@(idl_type_to_c(member.type))__are_equal(
&(lhs->@(member.name)), &(rhs->@(member.name))))
{
return false;
}
@[ elif isinstance(member.type, (AbstractGenericString, NamespacedType))]@
if (!@(basetype_to_c(member.type))__are_equal(
&(lhs->@(member.name)), &(rhs->@(member.name))))
{
return false;
}
@[ else]@
if (lhs->@(member.name) != rhs->@(member.name)) {
return false;
}
@[ end if]@
@[end for]@
return true;
}

bool
@(message_typename)__copy(
const @(message_typename) * input,
@(message_typename) * output)
{
if (!input || !output) {
return false;
}
@[for member in message.structure.members]@
// @(member.name)
@[ if isinstance(member.type, Array)]@
for (size_t i = 0; i < @(member.type.size); ++i) {
@[ if isinstance(member.type.value_type, (AbstractGenericString, NamespacedType))]@
if (!@(basetype_to_c(member.type.value_type))__copy(
&(input->@(member.name)[i]), &(output->@(member.name)[i])))
{
return false;
}
@[ else]@
output->@(member.name)[i] = input->@(member.name)[i];
@[ end if]@
}
@[ elif isinstance(member.type, AbstractSequence)]@
if (!@(idl_type_to_c(member.type))__copy(
&(input->@(member.name)), &(output->@(member.name))))
{
return false;
}
@[ elif isinstance(member.type, (AbstractGenericString, NamespacedType))]@
if (!@(basetype_to_c(member.type))__copy(
&(input->@(member.name)), &(output->@(member.name))))
{
return false;
}
@[ else]@
output->@(member.name) = input->@(member.name);
@[ end if]@
@[end for]@
return true;
}

@(message_typename) *
@(message_typename)__create()
{
Expand Down Expand Up @@ -343,3 +427,60 @@ void
}
free(array);
}

bool
@(array_typename)__are_equal(const @(array_typename) * lhs, const @(array_typename) * rhs)
{
if (!lhs || !rhs) {
return false;
}
if (lhs->size != rhs->size) {
return false;
}
for (size_t i = 0; i < lhs->size; ++i) {
if (!@(message_typename)__are_equal(&(lhs->data[i]), &(rhs->data[i]))) {
return false;
}
}
return true;
}

bool
@(array_typename)__copy(
const @(array_typename) * input,
@(array_typename) * output)
{
if (!input || !output) {
return false;
}
if (output->capacity < input->size) {
const size_t allocation_size =
input->size * sizeof(@(message_typename));
@(message_typename) * data =
(@(message_typename) *)realloc(output->data, allocation_size);
if (!data) {
return false;
}
for (size_t i = output->capacity; i < input->size; ++i) {
if (!@(message_typename)__init(&data[i])) {
/* free currently allocated and return false */
for (; i-- > output->capacity; ) {
@(message_typename)__fini(&data[i]);
}
free(data);
return false;
}
}
output->data = data;
output->capacity = input->size;
}
output->size = input->size;
for (size_t i = 0; i < input->size; ++i) {
if (!@(message_typename)__copy(
&(input->data[i]), &(output->data[i])))
{
return false;
}
}
return true;
}
53 changes: 53 additions & 0 deletions rosidl_generator_c/resource/msg__functions.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,32 @@ ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
void
@(message_typename)__destroy(@(message_typename) * msg);

/// Check for @(interface_path_to_string(interface_path)) message equality.
/**
* \param[in] lhs The message on the left hand size of the equality operator.
* \param[in] rhs The message on the right hand size of the equality operator.
* \return true if messages are equal, otherwise false.
*/
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
bool
@(message_typename)__are_equal(const @(message_typename) * lhs, const @(message_typename) * rhs);
/// Copy a @(interface_path_to_string(interface_path)) message.
/**
* This functions performs a deep copy, as opposed to the shallow copy that
* plain assignment yields.
*
* \param[in] input The source message pointer.
* \param[out] output The target message pointer, which must
* have been initialized before calling this function.
* \return true if successful, or false if either pointer is null
* or memory allocation fails.
*/
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
bool
@(message_typename)__copy(
const @(message_typename) * input,
@(message_typename) * output);

@#######################################################################
@# array functions
Expand Down Expand Up @@ -112,3 +138,30 @@ ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
void
@(array_typename)__destroy(@(array_typename) * array);

/// Check for @(interface_path_to_string(interface_path)) message array equality.
/**
* \param[in] lhs The message array on the left hand size of the equality operator.
* \param[in] rhs The message array on the right hand size of the equality operator.
* \return true if message arrays are equal in size and content, otherwise false.
*/
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
bool
@(array_typename)__are_equal(const @(array_typename) * lhs, const @(array_typename) * rhs);
/// Copy an array of @(interface_path_to_string(interface_path)) messages.
/**
* This functions performs a deep copy, as opposed to the shallow copy that
* plain assignment yields.
*
* \param[in] input The source array pointer.
* \param[out] output The target array pointer, which must
* have been initialized before calling this function.
* \return true if successful, or false if either pointer
* is null or memory allocation fails.
*/
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
bool
@(array_typename)__copy(
const @(array_typename) * input,
@(array_typename) * output);
113 changes: 113 additions & 0 deletions rosidl_generator_c/test/test_interfaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@
#define STRINGIFY(x) _STRINGIFY(x)
#define _STRINGIFY(x) #x

#define EXPECT_FALSE(arg) if (arg) { \
fputs(STRINGIFY(arg) " is not false\n", stderr); \
return 1; \
}
#define EXPECT_TRUE(arg) if (!(arg)) { \
fputs(STRINGIFY(arg) " is not true\n", stderr); \
return 1; \
}
#define EXPECT_EQ(arg1, arg2) if ((arg1) != (arg2)) { \
fputs(STRINGIFY(arg1) " != " STRINGIFY(arg2) "\n", stderr); \
return 1; \
Expand Down Expand Up @@ -189,6 +197,19 @@ int test_basic_types(void)
basic->uint64_value = UINT64_MAX;
EXPECT_EQ(UINT64_MAX, basic->uint64_value);

EXPECT_FALSE(rosidl_generator_c__msg__BasicTypes__are_equal(NULL, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__BasicTypes__are_equal(basic, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__BasicTypes__are_equal(NULL, basic));
EXPECT_TRUE(rosidl_generator_c__msg__BasicTypes__are_equal(basic, basic));

rosidl_generator_c__msg__BasicTypes * basic_copy = NULL;
basic_copy = rosidl_generator_c__msg__BasicTypes__create();
EXPECT_NE(basic_copy, NULL);
EXPECT_FALSE(rosidl_generator_c__msg__BasicTypes__are_equal(basic, basic_copy));
EXPECT_TRUE(rosidl_generator_c__msg__BasicTypes__copy(basic, basic_copy));
EXPECT_TRUE(rosidl_generator_c__msg__BasicTypes__are_equal(basic, basic_copy));
rosidl_generator_c__msg__BasicTypes__destroy(basic_copy);

rosidl_generator_c__msg__BasicTypes__destroy(basic);
return 0;
}
Expand Down Expand Up @@ -232,6 +253,20 @@ int test_defaults()
EXPECT_EQ(-40000000, def->int64_value);
EXPECT_EQ(50000000, def->uint64_value);

EXPECT_FALSE(rosidl_generator_c__msg__Defaults__are_equal(NULL, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__Defaults__are_equal(def, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__Defaults__are_equal(NULL, def));
EXPECT_TRUE(rosidl_generator_c__msg__Defaults__are_equal(def, def));

rosidl_generator_c__msg__Defaults * def_copy = NULL;
def_copy = rosidl_generator_c__msg__Defaults__create();
EXPECT_NE(def_copy, NULL);
def->bool_value = false; // mutate message to force a difference
EXPECT_FALSE(rosidl_generator_c__msg__Defaults__are_equal(def, def_copy));
EXPECT_TRUE(rosidl_generator_c__msg__Defaults__copy(def, def_copy));
EXPECT_TRUE(rosidl_generator_c__msg__Defaults__are_equal(def, def_copy));
rosidl_generator_c__msg__Defaults__destroy(def_copy);

rosidl_generator_c__msg__Defaults__destroy(def);
return 0;
}
Expand Down Expand Up @@ -447,6 +482,19 @@ int test_bounded_sequences()
EXPECT_EQ(0, strcmp(seq->string_values_default.data[1].data, "max value"));
EXPECT_EQ(0, strcmp(seq->string_values_default.data[2].data, "min value"));

EXPECT_FALSE(rosidl_generator_c__msg__BoundedSequences__are_equal(NULL, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__BoundedSequences__are_equal(seq, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__BoundedSequences__are_equal(NULL, seq));
EXPECT_TRUE(rosidl_generator_c__msg__BoundedSequences__are_equal(seq, seq));

rosidl_generator_c__msg__BoundedSequences * seq_copy = NULL;
seq_copy = rosidl_generator_c__msg__BoundedSequences__create();
EXPECT_NE(seq_copy, NULL);
EXPECT_FALSE(rosidl_generator_c__msg__BoundedSequences__are_equal(seq, seq_copy));
EXPECT_TRUE(rosidl_generator_c__msg__BoundedSequences__copy(seq, seq_copy));
EXPECT_TRUE(rosidl_generator_c__msg__BoundedSequences__are_equal(seq, seq_copy));
rosidl_generator_c__msg__BoundedSequences__destroy(seq_copy);

rosidl_generator_c__msg__BoundedSequences__destroy(seq);
return 0;
}
Expand Down Expand Up @@ -663,6 +711,19 @@ int test_unbounded_sequences()
EXPECT_EQ(0, strcmp(seq->string_values_default.data[1].data, "max value"));
EXPECT_EQ(0, strcmp(seq->string_values_default.data[2].data, "min value"));

EXPECT_FALSE(rosidl_generator_c__msg__UnboundedSequences__are_equal(NULL, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__UnboundedSequences__are_equal(seq, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__UnboundedSequences__are_equal(NULL, seq));
EXPECT_TRUE(rosidl_generator_c__msg__UnboundedSequences__are_equal(seq, seq));

rosidl_generator_c__msg__UnboundedSequences * seq_copy = NULL;
seq_copy = rosidl_generator_c__msg__UnboundedSequences__create();
EXPECT_NE(seq_copy, NULL);
EXPECT_FALSE(rosidl_generator_c__msg__UnboundedSequences__are_equal(seq, seq_copy));
EXPECT_TRUE(rosidl_generator_c__msg__UnboundedSequences__copy(seq, seq_copy));
EXPECT_TRUE(rosidl_generator_c__msg__UnboundedSequences__are_equal(seq, seq_copy));
rosidl_generator_c__msg__UnboundedSequences__destroy(seq_copy);

rosidl_generator_c__msg__UnboundedSequences__destroy(seq);
return 0;
}
Expand Down Expand Up @@ -694,6 +755,19 @@ int test_strings()
EXPECT_EQ(0, strcmp(str->bounded_string_value_default1.data, "Hello world!"));
EXPECT_EQ(0, strcmp(str->bounded_string_value_default5.data, "Hello\"world!"));

EXPECT_FALSE(rosidl_generator_c__msg__Strings__are_equal(NULL, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__Strings__are_equal(str, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__Strings__are_equal(NULL, str));
EXPECT_TRUE(rosidl_generator_c__msg__Strings__are_equal(str, str));

rosidl_generator_c__msg__Strings * str_copy = NULL;
str_copy = rosidl_generator_c__msg__Strings__create();
EXPECT_NE(str_copy, NULL);
EXPECT_FALSE(rosidl_generator_c__msg__Strings__are_equal(str, str_copy));
EXPECT_TRUE(rosidl_generator_c__msg__Strings__copy(str, str_copy));
EXPECT_TRUE(rosidl_generator_c__msg__Strings__are_equal(str, str_copy));
rosidl_generator_c__msg__Strings__destroy(str_copy);

rosidl_generator_c__msg__Strings__destroy(str);
return 0;
}
Expand Down Expand Up @@ -732,6 +806,19 @@ int test_nested()
EXPECT_EQ(-40000000, nested->basic_types_value.int64_value);
EXPECT_EQ(50000000, nested->basic_types_value.uint64_value);

EXPECT_FALSE(rosidl_generator_c__msg__Nested__are_equal(NULL, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__Nested__are_equal(nested, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__Nested__are_equal(NULL, nested));
EXPECT_TRUE(rosidl_generator_c__msg__Nested__are_equal(nested, nested));

rosidl_generator_c__msg__Nested * nested_copy = NULL;
nested_copy = rosidl_generator_c__msg__Nested__create();
EXPECT_NE(nested_copy, NULL);
EXPECT_FALSE(rosidl_generator_c__msg__Nested__are_equal(nested, nested_copy));
EXPECT_TRUE(rosidl_generator_c__msg__Nested__copy(nested, nested_copy));
EXPECT_TRUE(rosidl_generator_c__msg__Nested__are_equal(nested, nested_copy));
rosidl_generator_c__msg__Nested__destroy(nested_copy);

rosidl_generator_c__msg__Nested__destroy(nested);
return 0;
}
Expand Down Expand Up @@ -971,6 +1058,19 @@ int test_multi_nested()
EXPECT_EQ(UINT64_MAX, msg->array_of_arrays[0].uint64_values_default[2]);
}

EXPECT_FALSE(rosidl_generator_c__msg__MultiNested__are_equal(NULL, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__MultiNested__are_equal(msg, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__MultiNested__are_equal(NULL, msg));
EXPECT_TRUE(rosidl_generator_c__msg__MultiNested__are_equal(msg, msg));

rosidl_generator_c__msg__MultiNested * msg_copy = NULL;
msg_copy = rosidl_generator_c__msg__MultiNested__create();
EXPECT_NE(msg_copy, NULL);
EXPECT_FALSE(rosidl_generator_c__msg__MultiNested__are_equal(msg, msg_copy));
EXPECT_TRUE(rosidl_generator_c__msg__MultiNested__copy(msg, msg_copy));
EXPECT_TRUE(rosidl_generator_c__msg__MultiNested__are_equal(msg, msg_copy));
rosidl_generator_c__msg__MultiNested__destroy(msg_copy);

rosidl_generator_c__msg__MultiNested__destroy(msg);
return 0;
}
Expand Down Expand Up @@ -1182,6 +1282,19 @@ int test_arrays()
EXPECT_EQ(0, strcmp(arr->string_values_default[1].data, "max value"));
EXPECT_EQ(0, strcmp(arr->string_values_default[2].data, "min value"));

EXPECT_FALSE(rosidl_generator_c__msg__Arrays__are_equal(NULL, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__Arrays__are_equal(arr, NULL));
EXPECT_FALSE(rosidl_generator_c__msg__Arrays__are_equal(NULL, arr));
EXPECT_TRUE(rosidl_generator_c__msg__Arrays__are_equal(arr, arr));

rosidl_generator_c__msg__Arrays * arr_copy = NULL;
arr_copy = rosidl_generator_c__msg__Arrays__create();
EXPECT_NE(arr_copy, NULL);
EXPECT_FALSE(rosidl_generator_c__msg__Arrays__are_equal(arr, arr_copy));
EXPECT_TRUE(rosidl_generator_c__msg__Arrays__copy(arr, arr_copy));
EXPECT_TRUE(rosidl_generator_c__msg__Arrays__are_equal(arr, arr_copy));
rosidl_generator_c__msg__Arrays__destroy(arr_copy);

rosidl_generator_c__msg__Arrays__destroy(arr);
return 0;
}
Loading

0 comments on commit b6e9005

Please sign in to comment.