Skip to content

Commit e9eea15

Browse files
nnmmhidmic
andauthored
Galactic backport of #648 and #650 (#668)
* Implement equality operator function for C messages. (#648) Signed-off-by: Michel Hidalgo <[email protected]> * Implement copy function for C messages (#650) Signed-off-by: Michel Hidalgo <[email protected]> * Replace rcutils_allocator with the system allocator Signed-off-by: Nikolai Morin <[email protected]> * Set the output size unconditionally when copying sequences Signed-off-by: Nikolai Morin <[email protected]> Co-authored-by: Michel Hidalgo <[email protected]>
1 parent 7d95d64 commit e9eea15

File tree

12 files changed

+1037
-23
lines changed

12 files changed

+1037
-23
lines changed

rosidl_generator_c/resource/msg__functions.c.em

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,90 @@ for line in lines:
232232
}@
233233
}
234234

235+
bool
236+
@(message_typename)__are_equal(const @(message_typename) * lhs, const @(message_typename) * rhs)
237+
{
238+
if (!lhs || !rhs) {
239+
return false;
240+
}
241+
@[for member in message.structure.members]@
242+
// @(member.name)
243+
@[ if isinstance(member.type, Array)]@
244+
for (size_t i = 0; i < @(member.type.size); ++i) {
245+
@[ if isinstance(member.type.value_type, (AbstractGenericString, NamespacedType))]@
246+
if (!@(basetype_to_c(member.type.value_type))__are_equal(
247+
&(lhs->@(member.name)[i]), &(rhs->@(member.name)[i])))
248+
{
249+
return false;
250+
}
251+
@[ else]@
252+
if (lhs->@(member.name)[i] != rhs->@(member.name)[i]) {
253+
return false;
254+
}
255+
@[ end if]@
256+
}
257+
@[ elif isinstance(member.type, AbstractSequence)]@
258+
if (!@(idl_type_to_c(member.type))__are_equal(
259+
&(lhs->@(member.name)), &(rhs->@(member.name))))
260+
{
261+
return false;
262+
}
263+
@[ elif isinstance(member.type, (AbstractGenericString, NamespacedType))]@
264+
if (!@(basetype_to_c(member.type))__are_equal(
265+
&(lhs->@(member.name)), &(rhs->@(member.name))))
266+
{
267+
return false;
268+
}
269+
@[ else]@
270+
if (lhs->@(member.name) != rhs->@(member.name)) {
271+
return false;
272+
}
273+
@[ end if]@
274+
@[end for]@
275+
return true;
276+
}
277+
278+
bool
279+
@(message_typename)__copy(
280+
const @(message_typename) * input,
281+
@(message_typename) * output)
282+
{
283+
if (!input || !output) {
284+
return false;
285+
}
286+
@[for member in message.structure.members]@
287+
// @(member.name)
288+
@[ if isinstance(member.type, Array)]@
289+
for (size_t i = 0; i < @(member.type.size); ++i) {
290+
@[ if isinstance(member.type.value_type, (AbstractGenericString, NamespacedType))]@
291+
if (!@(basetype_to_c(member.type.value_type))__copy(
292+
&(input->@(member.name)[i]), &(output->@(member.name)[i])))
293+
{
294+
return false;
295+
}
296+
@[ else]@
297+
output->@(member.name)[i] = input->@(member.name)[i];
298+
@[ end if]@
299+
}
300+
@[ elif isinstance(member.type, AbstractSequence)]@
301+
if (!@(idl_type_to_c(member.type))__copy(
302+
&(input->@(member.name)), &(output->@(member.name))))
303+
{
304+
return false;
305+
}
306+
@[ elif isinstance(member.type, (AbstractGenericString, NamespacedType))]@
307+
if (!@(basetype_to_c(member.type))__copy(
308+
&(input->@(member.name)), &(output->@(member.name))))
309+
{
310+
return false;
311+
}
312+
@[ else]@
313+
output->@(member.name) = input->@(member.name);
314+
@[ end if]@
315+
@[end for]@
316+
return true;
317+
}
318+
235319
@(message_typename) *
236320
@(message_typename)__create()
237321
{
@@ -343,3 +427,60 @@ void
343427
}
344428
free(array);
345429
}
430+
431+
bool
432+
@(array_typename)__are_equal(const @(array_typename) * lhs, const @(array_typename) * rhs)
433+
{
434+
if (!lhs || !rhs) {
435+
return false;
436+
}
437+
if (lhs->size != rhs->size) {
438+
return false;
439+
}
440+
for (size_t i = 0; i < lhs->size; ++i) {
441+
if (!@(message_typename)__are_equal(&(lhs->data[i]), &(rhs->data[i]))) {
442+
return false;
443+
}
444+
}
445+
return true;
446+
}
447+
448+
bool
449+
@(array_typename)__copy(
450+
const @(array_typename) * input,
451+
@(array_typename) * output)
452+
{
453+
if (!input || !output) {
454+
return false;
455+
}
456+
if (output->capacity < input->size) {
457+
const size_t allocation_size =
458+
input->size * sizeof(@(message_typename));
459+
@(message_typename) * data =
460+
(@(message_typename) *)realloc(output->data, allocation_size);
461+
if (!data) {
462+
return false;
463+
}
464+
for (size_t i = output->capacity; i < input->size; ++i) {
465+
if (!@(message_typename)__init(&data[i])) {
466+
/* free currently allocated and return false */
467+
for (; i-- > output->capacity; ) {
468+
@(message_typename)__fini(&data[i]);
469+
}
470+
free(data);
471+
return false;
472+
}
473+
}
474+
output->data = data;
475+
output->capacity = input->size;
476+
}
477+
output->size = input->size;
478+
for (size_t i = 0; i < input->size; ++i) {
479+
if (!@(message_typename)__copy(
480+
&(input->data[i]), &(output->data[i])))
481+
{
482+
return false;
483+
}
484+
}
485+
return true;
486+
}

rosidl_generator_c/resource/msg__functions.h.em

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,32 @@ ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
5959
void
6060
@(message_typename)__destroy(@(message_typename) * msg);
6161

62+
/// Check for @(interface_path_to_string(interface_path)) message equality.
63+
/**
64+
* \param[in] lhs The message on the left hand size of the equality operator.
65+
* \param[in] rhs The message on the right hand size of the equality operator.
66+
* \return true if messages are equal, otherwise false.
67+
*/
68+
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
69+
bool
70+
@(message_typename)__are_equal(const @(message_typename) * lhs, const @(message_typename) * rhs);
71+
72+
/// Copy a @(interface_path_to_string(interface_path)) message.
73+
/**
74+
* This functions performs a deep copy, as opposed to the shallow copy that
75+
* plain assignment yields.
76+
*
77+
* \param[in] input The source message pointer.
78+
* \param[out] output The target message pointer, which must
79+
* have been initialized before calling this function.
80+
* \return true if successful, or false if either pointer is null
81+
* or memory allocation fails.
82+
*/
83+
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
84+
bool
85+
@(message_typename)__copy(
86+
const @(message_typename) * input,
87+
@(message_typename) * output);
6288

6389
@#######################################################################
6490
@# array functions
@@ -112,3 +138,30 @@ ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
112138
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
113139
void
114140
@(array_typename)__destroy(@(array_typename) * array);
141+
142+
/// Check for @(interface_path_to_string(interface_path)) message array equality.
143+
/**
144+
* \param[in] lhs The message array on the left hand size of the equality operator.
145+
* \param[in] rhs The message array on the right hand size of the equality operator.
146+
* \return true if message arrays are equal in size and content, otherwise false.
147+
*/
148+
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
149+
bool
150+
@(array_typename)__are_equal(const @(array_typename) * lhs, const @(array_typename) * rhs);
151+
152+
/// Copy an array of @(interface_path_to_string(interface_path)) messages.
153+
/**
154+
* This functions performs a deep copy, as opposed to the shallow copy that
155+
* plain assignment yields.
156+
*
157+
* \param[in] input The source array pointer.
158+
* \param[out] output The target array pointer, which must
159+
* have been initialized before calling this function.
160+
* \return true if successful, or false if either pointer
161+
* is null or memory allocation fails.
162+
*/
163+
ROSIDL_GENERATOR_C_PUBLIC_@(package_name)
164+
bool
165+
@(array_typename)__copy(
166+
const @(array_typename) * input,
167+
@(array_typename) * output);

rosidl_generator_c/test/test_interfaces.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@
4949
#define STRINGIFY(x) _STRINGIFY(x)
5050
#define _STRINGIFY(x) #x
5151

52+
#define EXPECT_FALSE(arg) if (arg) { \
53+
fputs(STRINGIFY(arg) " is not false\n", stderr); \
54+
return 1; \
55+
}
56+
#define EXPECT_TRUE(arg) if (!(arg)) { \
57+
fputs(STRINGIFY(arg) " is not true\n", stderr); \
58+
return 1; \
59+
}
5260
#define EXPECT_EQ(arg1, arg2) if ((arg1) != (arg2)) { \
5361
fputs(STRINGIFY(arg1) " != " STRINGIFY(arg2) "\n", stderr); \
5462
return 1; \
@@ -189,6 +197,19 @@ int test_basic_types(void)
189197
basic->uint64_value = UINT64_MAX;
190198
EXPECT_EQ(UINT64_MAX, basic->uint64_value);
191199

200+
EXPECT_FALSE(rosidl_generator_c__msg__BasicTypes__are_equal(NULL, NULL));
201+
EXPECT_FALSE(rosidl_generator_c__msg__BasicTypes__are_equal(basic, NULL));
202+
EXPECT_FALSE(rosidl_generator_c__msg__BasicTypes__are_equal(NULL, basic));
203+
EXPECT_TRUE(rosidl_generator_c__msg__BasicTypes__are_equal(basic, basic));
204+
205+
rosidl_generator_c__msg__BasicTypes * basic_copy = NULL;
206+
basic_copy = rosidl_generator_c__msg__BasicTypes__create();
207+
EXPECT_NE(basic_copy, NULL);
208+
EXPECT_FALSE(rosidl_generator_c__msg__BasicTypes__are_equal(basic, basic_copy));
209+
EXPECT_TRUE(rosidl_generator_c__msg__BasicTypes__copy(basic, basic_copy));
210+
EXPECT_TRUE(rosidl_generator_c__msg__BasicTypes__are_equal(basic, basic_copy));
211+
rosidl_generator_c__msg__BasicTypes__destroy(basic_copy);
212+
192213
rosidl_generator_c__msg__BasicTypes__destroy(basic);
193214
return 0;
194215
}
@@ -232,6 +253,20 @@ int test_defaults()
232253
EXPECT_EQ(-40000000, def->int64_value);
233254
EXPECT_EQ(50000000, def->uint64_value);
234255

256+
EXPECT_FALSE(rosidl_generator_c__msg__Defaults__are_equal(NULL, NULL));
257+
EXPECT_FALSE(rosidl_generator_c__msg__Defaults__are_equal(def, NULL));
258+
EXPECT_FALSE(rosidl_generator_c__msg__Defaults__are_equal(NULL, def));
259+
EXPECT_TRUE(rosidl_generator_c__msg__Defaults__are_equal(def, def));
260+
261+
rosidl_generator_c__msg__Defaults * def_copy = NULL;
262+
def_copy = rosidl_generator_c__msg__Defaults__create();
263+
EXPECT_NE(def_copy, NULL);
264+
def->bool_value = false; // mutate message to force a difference
265+
EXPECT_FALSE(rosidl_generator_c__msg__Defaults__are_equal(def, def_copy));
266+
EXPECT_TRUE(rosidl_generator_c__msg__Defaults__copy(def, def_copy));
267+
EXPECT_TRUE(rosidl_generator_c__msg__Defaults__are_equal(def, def_copy));
268+
rosidl_generator_c__msg__Defaults__destroy(def_copy);
269+
235270
rosidl_generator_c__msg__Defaults__destroy(def);
236271
return 0;
237272
}
@@ -447,6 +482,19 @@ int test_bounded_sequences()
447482
EXPECT_EQ(0, strcmp(seq->string_values_default.data[1].data, "max value"));
448483
EXPECT_EQ(0, strcmp(seq->string_values_default.data[2].data, "min value"));
449484

485+
EXPECT_FALSE(rosidl_generator_c__msg__BoundedSequences__are_equal(NULL, NULL));
486+
EXPECT_FALSE(rosidl_generator_c__msg__BoundedSequences__are_equal(seq, NULL));
487+
EXPECT_FALSE(rosidl_generator_c__msg__BoundedSequences__are_equal(NULL, seq));
488+
EXPECT_TRUE(rosidl_generator_c__msg__BoundedSequences__are_equal(seq, seq));
489+
490+
rosidl_generator_c__msg__BoundedSequences * seq_copy = NULL;
491+
seq_copy = rosidl_generator_c__msg__BoundedSequences__create();
492+
EXPECT_NE(seq_copy, NULL);
493+
EXPECT_FALSE(rosidl_generator_c__msg__BoundedSequences__are_equal(seq, seq_copy));
494+
EXPECT_TRUE(rosidl_generator_c__msg__BoundedSequences__copy(seq, seq_copy));
495+
EXPECT_TRUE(rosidl_generator_c__msg__BoundedSequences__are_equal(seq, seq_copy));
496+
rosidl_generator_c__msg__BoundedSequences__destroy(seq_copy);
497+
450498
rosidl_generator_c__msg__BoundedSequences__destroy(seq);
451499
return 0;
452500
}
@@ -663,6 +711,19 @@ int test_unbounded_sequences()
663711
EXPECT_EQ(0, strcmp(seq->string_values_default.data[1].data, "max value"));
664712
EXPECT_EQ(0, strcmp(seq->string_values_default.data[2].data, "min value"));
665713

714+
EXPECT_FALSE(rosidl_generator_c__msg__UnboundedSequences__are_equal(NULL, NULL));
715+
EXPECT_FALSE(rosidl_generator_c__msg__UnboundedSequences__are_equal(seq, NULL));
716+
EXPECT_FALSE(rosidl_generator_c__msg__UnboundedSequences__are_equal(NULL, seq));
717+
EXPECT_TRUE(rosidl_generator_c__msg__UnboundedSequences__are_equal(seq, seq));
718+
719+
rosidl_generator_c__msg__UnboundedSequences * seq_copy = NULL;
720+
seq_copy = rosidl_generator_c__msg__UnboundedSequences__create();
721+
EXPECT_NE(seq_copy, NULL);
722+
EXPECT_FALSE(rosidl_generator_c__msg__UnboundedSequences__are_equal(seq, seq_copy));
723+
EXPECT_TRUE(rosidl_generator_c__msg__UnboundedSequences__copy(seq, seq_copy));
724+
EXPECT_TRUE(rosidl_generator_c__msg__UnboundedSequences__are_equal(seq, seq_copy));
725+
rosidl_generator_c__msg__UnboundedSequences__destroy(seq_copy);
726+
666727
rosidl_generator_c__msg__UnboundedSequences__destroy(seq);
667728
return 0;
668729
}
@@ -694,6 +755,19 @@ int test_strings()
694755
EXPECT_EQ(0, strcmp(str->bounded_string_value_default1.data, "Hello world!"));
695756
EXPECT_EQ(0, strcmp(str->bounded_string_value_default5.data, "Hello\"world!"));
696757

758+
EXPECT_FALSE(rosidl_generator_c__msg__Strings__are_equal(NULL, NULL));
759+
EXPECT_FALSE(rosidl_generator_c__msg__Strings__are_equal(str, NULL));
760+
EXPECT_FALSE(rosidl_generator_c__msg__Strings__are_equal(NULL, str));
761+
EXPECT_TRUE(rosidl_generator_c__msg__Strings__are_equal(str, str));
762+
763+
rosidl_generator_c__msg__Strings * str_copy = NULL;
764+
str_copy = rosidl_generator_c__msg__Strings__create();
765+
EXPECT_NE(str_copy, NULL);
766+
EXPECT_FALSE(rosidl_generator_c__msg__Strings__are_equal(str, str_copy));
767+
EXPECT_TRUE(rosidl_generator_c__msg__Strings__copy(str, str_copy));
768+
EXPECT_TRUE(rosidl_generator_c__msg__Strings__are_equal(str, str_copy));
769+
rosidl_generator_c__msg__Strings__destroy(str_copy);
770+
697771
rosidl_generator_c__msg__Strings__destroy(str);
698772
return 0;
699773
}
@@ -732,6 +806,19 @@ int test_nested()
732806
EXPECT_EQ(-40000000, nested->basic_types_value.int64_value);
733807
EXPECT_EQ(50000000, nested->basic_types_value.uint64_value);
734808

809+
EXPECT_FALSE(rosidl_generator_c__msg__Nested__are_equal(NULL, NULL));
810+
EXPECT_FALSE(rosidl_generator_c__msg__Nested__are_equal(nested, NULL));
811+
EXPECT_FALSE(rosidl_generator_c__msg__Nested__are_equal(NULL, nested));
812+
EXPECT_TRUE(rosidl_generator_c__msg__Nested__are_equal(nested, nested));
813+
814+
rosidl_generator_c__msg__Nested * nested_copy = NULL;
815+
nested_copy = rosidl_generator_c__msg__Nested__create();
816+
EXPECT_NE(nested_copy, NULL);
817+
EXPECT_FALSE(rosidl_generator_c__msg__Nested__are_equal(nested, nested_copy));
818+
EXPECT_TRUE(rosidl_generator_c__msg__Nested__copy(nested, nested_copy));
819+
EXPECT_TRUE(rosidl_generator_c__msg__Nested__are_equal(nested, nested_copy));
820+
rosidl_generator_c__msg__Nested__destroy(nested_copy);
821+
735822
rosidl_generator_c__msg__Nested__destroy(nested);
736823
return 0;
737824
}
@@ -971,6 +1058,19 @@ int test_multi_nested()
9711058
EXPECT_EQ(UINT64_MAX, msg->array_of_arrays[0].uint64_values_default[2]);
9721059
}
9731060

1061+
EXPECT_FALSE(rosidl_generator_c__msg__MultiNested__are_equal(NULL, NULL));
1062+
EXPECT_FALSE(rosidl_generator_c__msg__MultiNested__are_equal(msg, NULL));
1063+
EXPECT_FALSE(rosidl_generator_c__msg__MultiNested__are_equal(NULL, msg));
1064+
EXPECT_TRUE(rosidl_generator_c__msg__MultiNested__are_equal(msg, msg));
1065+
1066+
rosidl_generator_c__msg__MultiNested * msg_copy = NULL;
1067+
msg_copy = rosidl_generator_c__msg__MultiNested__create();
1068+
EXPECT_NE(msg_copy, NULL);
1069+
EXPECT_FALSE(rosidl_generator_c__msg__MultiNested__are_equal(msg, msg_copy));
1070+
EXPECT_TRUE(rosidl_generator_c__msg__MultiNested__copy(msg, msg_copy));
1071+
EXPECT_TRUE(rosidl_generator_c__msg__MultiNested__are_equal(msg, msg_copy));
1072+
rosidl_generator_c__msg__MultiNested__destroy(msg_copy);
1073+
9741074
rosidl_generator_c__msg__MultiNested__destroy(msg);
9751075
return 0;
9761076
}
@@ -1182,6 +1282,19 @@ int test_arrays()
11821282
EXPECT_EQ(0, strcmp(arr->string_values_default[1].data, "max value"));
11831283
EXPECT_EQ(0, strcmp(arr->string_values_default[2].data, "min value"));
11841284

1285+
EXPECT_FALSE(rosidl_generator_c__msg__Arrays__are_equal(NULL, NULL));
1286+
EXPECT_FALSE(rosidl_generator_c__msg__Arrays__are_equal(arr, NULL));
1287+
EXPECT_FALSE(rosidl_generator_c__msg__Arrays__are_equal(NULL, arr));
1288+
EXPECT_TRUE(rosidl_generator_c__msg__Arrays__are_equal(arr, arr));
1289+
1290+
rosidl_generator_c__msg__Arrays * arr_copy = NULL;
1291+
arr_copy = rosidl_generator_c__msg__Arrays__create();
1292+
EXPECT_NE(arr_copy, NULL);
1293+
EXPECT_FALSE(rosidl_generator_c__msg__Arrays__are_equal(arr, arr_copy));
1294+
EXPECT_TRUE(rosidl_generator_c__msg__Arrays__copy(arr, arr_copy));
1295+
EXPECT_TRUE(rosidl_generator_c__msg__Arrays__are_equal(arr, arr_copy));
1296+
rosidl_generator_c__msg__Arrays__destroy(arr_copy);
1297+
11851298
rosidl_generator_c__msg__Arrays__destroy(arr);
11861299
return 0;
11871300
}

0 commit comments

Comments
 (0)