Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions rosidl_generator_cpp/resource/idl__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ include_directives = set()
#include <vector>

#include "rosidl_runtime_cpp/bounded_vector.hpp"
#include "rosidl_runtime_cpp/deprecated_helper_array.hpp"
#include "rosidl_runtime_cpp/deprecated_helper_bounded_vector.hpp"
#include "rosidl_runtime_cpp/deprecated_helper_byte.hpp"
#include "rosidl_runtime_cpp/deprecated_helper_vector.hpp"
#include "rosidl_runtime_cpp/message_initialization.hpp"

@#######################################################################
Expand Down
8 changes: 7 additions & 1 deletion rosidl_generator_cpp/resource/msg__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,15 @@ non_defaulted_zero_initialized_members = [
@[ else]@
static constexpr @(MSG_TYPE_TO_CPP[constant.type.typename]) @(constant.name) =
@[ if isinstance(constant.type, BasicType)]@
@[ if constant.type.typename in (*INTEGER_TYPES, *CHARACTER_TYPES, BOOLEAN_TYPE, OCTET_TYPE)]@
@[ if constant.type.typename in (*INTEGER_TYPES, *CHARACTER_TYPES, BOOLEAN_TYPE)]@
@(int(constant.value))@
@[ if constant.type.typename in UNSIGNED_INTEGER_TYPES]@
u@
@[ end if]@
@[ elif constant.type.typename == 'float']@
@(constant.value)f@
@[ elif constant.type.typename == OCTET_TYPE]@
std::byte{@(constant.value)}@
@[ else]@
@(constant.value)@
@[ end if];
Expand Down Expand Up @@ -307,7 +309,11 @@ u@
(void)other;
@[end if]@
@[for member in message.structure.members]@
@[ if isinstance(member.type, BasicType) and member.type.typename == OCTET_TYPE]@
if (static_cast<std::byte>(this->@(member.name)) != static_cast<std::byte>(other.@(member.name))) {
@[ else]@
if (this->@(member.name) != other.@(member.name)) {
@[ end if]@
return false;
}
@[end for]@
Expand Down
23 changes: 19 additions & 4 deletions rosidl_generator_cpp/resource/msg__traits.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ from rosidl_parser.definition import EMPTY_STRUCTURE_REQUIRED_MEMBER_NAME
from rosidl_parser.definition import NamespacedType
from rosidl_parser.definition import AbstractSequence
from rosidl_parser.definition import UnboundedSequence
from rosidl_parser.definition import OCTET_TYPE

message_namespace = '::'.join(message.structure.namespaced_type.namespaces)
message_typename = '::'.join(message.structure.namespaced_type.namespaced_name())
Expand Down Expand Up @@ -93,8 +94,10 @@ inline void to_flow_style_yaml(
{
@[ if isinstance(member.type, BasicType)]@
out << "@(member.name): ";
@[ if member.type.typename in ('octet', 'char', 'wchar')]@
@[ if member.type.typename in ('char', 'wchar')]@
rosidl_generator_traits::character_value_to_yaml(msg.@(member.name), out);
@[ elif member.type.typename == OCTET_TYPE]@
rosidl_generator_traits::value_to_yaml(static_cast<std::byte>(msg.@(member.name)), out);
@[ else]@
rosidl_generator_traits::value_to_yaml(msg.@(member.name), out);
@[ end if]@
Expand All @@ -110,9 +113,14 @@ inline void to_flow_style_yaml(
} else {
out << "@(member.name): [";
size_t pending_items = msg.@(member.name).size();
@[ if isinstance(member.type.value_type, BasicType) and member.type.value_type.typename == OCTET_TYPE]@
for (size_t i = 0; i < msg.@(member.name).size(); i++) {
auto item = static_cast<std::byte>(msg.@(member.name)[i]);
@[ else]@
for (auto item : msg.@(member.name)) {
@[ end if]@
@[ if isinstance(member.type.value_type, BasicType)]@
@[ if member.type.value_type.typename in ('octet', 'char', 'wchar')]@
@[ if member.type.value_type.typename in ('char', 'wchar')]@
rosidl_generator_traits::character_value_to_yaml(item, out);
@[ else]@
rosidl_generator_traits::value_to_yaml(item, out);
Expand Down Expand Up @@ -158,8 +166,10 @@ inline void to_block_style_yaml(
}
@[ if isinstance(member.type, BasicType)]@
out << "@(member.name): ";
@[ if member.type.typename in ('octet', 'char', 'wchar')]@
@[ if member.type.typename in ('char', 'wchar')]@
rosidl_generator_traits::character_value_to_yaml(msg.@(member.name), out);
@[ elif member.type.typename == OCTET_TYPE]@
rosidl_generator_traits::value_to_yaml(static_cast<std::byte>(msg.@(member.name)), out);
@[ else]@
rosidl_generator_traits::value_to_yaml(msg.@(member.name), out);
@[ end if]@
Expand All @@ -176,13 +186,18 @@ inline void to_block_style_yaml(
out << "@(member.name): []\n";
} else {
out << "@(member.name):\n";
@[ if isinstance(member.type.value_type, BasicType) and member.type.value_type.typename == OCTET_TYPE]@
for (size_t i = 0; i < msg.@(member.name).size(); i++) {
auto item = static_cast<std::byte>(msg.@(member.name)[i]);
@[ else]@
for (auto item : msg.@(member.name)) {
@[ end if]@
if (indentation > 0) {
out << std::string(indentation, ' ');
}
@[ if isinstance(member.type.value_type, BasicType)]@
out << "- ";
@[ if member.type.value_type.typename in ('octet', 'char', 'wchar')]@
@[ if member.type.value_type.typename in ('char', 'wchar')]@
rosidl_generator_traits::character_value_to_yaml(item, out);
@[ else]@
rosidl_generator_traits::value_to_yaml(item, out);
Expand Down
46 changes: 44 additions & 2 deletions rosidl_generator_cpp/rosidl_generator_cpp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,20 @@
from rosidl_parser.definition import AbstractNestedType
from rosidl_parser.definition import AbstractSequence
from rosidl_parser.definition import AbstractString
from rosidl_parser.definition import AbstractType
from rosidl_parser.definition import AbstractWString
from rosidl_parser.definition import Array
from rosidl_parser.definition import BasicType
from rosidl_parser.definition import BoundedSequence
from rosidl_parser.definition import FLOATING_POINT_TYPES
from rosidl_parser.definition import NamespacedType
from rosidl_parser.definition import OCTET_TYPE
from rosidl_parser.definition import UnboundedSequence
from rosidl_pycommon import generate_files

# UCHAR_ALLOC_TYPE = 'unsigned char'
UCHAR_ALLOC_TYPE = 'std::byte'


def generate_cpp(generator_arguments_file) -> List[str]:
mapping = {
Expand Down Expand Up @@ -55,8 +60,8 @@ def prefix_with_bom_if_necessary(content: str) -> str:

MSG_TYPE_TO_CPP = {
'boolean': 'bool',
'octet': 'unsigned char', # TODO change to std::byte with C++17
'char': 'unsigned char', # TODO change to char8_t with C++20
'octet': 'rosidl_runtime_cpp::DeprecatedHelperByte', # TODO: M Turtle+ switch to std::byte
'char': 'unsigned char', # TODO: Should be char8_t in C++ 20
'wchar': 'char16_t',
'float': 'float',
'double': 'double',
Expand Down Expand Up @@ -103,6 +108,36 @@ def msg_type_only_to_cpp(type_):
return cpp_type


def is_in_process_of_deprecation(type_: AbstractType) -> bool:
"""Return true if type_ is octet or a container of octet."""
if isinstance(type_, BasicType) and type_.typename == OCTET_TYPE:
return True
elif (isinstance(type_, AbstractNestedType) and
isinstance(type_.value_type, BasicType) and
type_.value_type.typename == OCTET_TYPE):
return True
else:
return False


def special_typename_for_deprecation(type_: AbstractType) -> str:
"""Return special deprecation helper names."""
if isinstance(type_, BasicType) and type_.typename == OCTET_TYPE:
return 'rosidl_runtime_cpp::DeprecatedHelperByte'
elif isinstance(type_, UnboundedSequence):
return ('rosidl_runtime_cpp::DeprecatedHelperVector<typename '
'std::allocator_traits<ContainerAllocator>::template '
f'rebind_alloc<{UCHAR_ALLOC_TYPE}>>')
elif isinstance(type_, BoundedSequence):
return (f'rosidl_runtime_cpp::DeprecatedHelperBoundedVector<{type_.maximum_size}, '
'typename std::allocator_traits'
f'<ContainerAllocator>::template rebind_alloc<{UCHAR_ALLOC_TYPE}>>')
elif isinstance(type_, Array):
return f'rosidl_runtime_cpp::DeprecatedHelperArray<{type_.size}>'
else:
assert False, f'type: {type_} should not be called.'


def msg_type_to_cpp(type_):
"""
Convert a message type into the C++ declaration, along with the array type.
Expand All @@ -114,6 +149,9 @@ def msg_type_to_cpp(type_):
@param type_: The message type
@type type_: rosidl_parser.Type
"""
if is_in_process_of_deprecation(type_):
return special_typename_for_deprecation(type_)

cpp_type = msg_type_only_to_cpp(type_)

if isinstance(type_, AbstractNestedType):
Expand Down Expand Up @@ -196,6 +234,10 @@ def primitive_value_to_cpp(type_, value):
if type_.typename == 'boolean':
return 'true' if value else 'false'

if type_.typename == 'octet':
# return str(value)
return f'std::byte{{{value}}}'

if type_.typename in [
'char', 'octet'
]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#define ROSIDL_GENERATOR_CPP__TEST_ARRAY_GENERATOR_HPP_

#include <climits>
#include <cstddef>
#include <cstdint>
#include <random>
#include <string>
#include <type_traits>
Expand Down Expand Up @@ -44,6 +46,37 @@ void test_vector_fill(
}
}

/**
* Helper function to generate a test pattern for byte type.
* Minimum and maximum values for the type and distributed values in the middle.
* @param C Container (vector, array, etc) to be filled
* @param size How many elements to fill in. Must size<=container_size
* @param min Minimum value in the range to fill.
* @param max Maximum value in the range to fill.
*/
template<
typename C,
typename std::enable_if<
std::is_same<typename C::value_type, std::byte>::value
>::type * = nullptr
>
void test_vector_fill(
C * container, size_t size,
typename C::value_type min, typename C::value_type max)
{
if (size > 0 && min < max) {
int step = (std::to_integer<int>(max) - std::to_integer<int>(min)) / static_cast<int>(size);

(*container)[0] = min;
for (size_t i = 1; i < size - 1; i++) {
int val = std::to_integer<int>(min) + i * step;
(*container)[i] = static_cast<std::byte>(val);
}
(*container)[size - 1] = max;
}
}


/**
* Helper function to generate a test pattern for integer number types.
* The template type parameter must be an integer number type.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
#include <array>
#include <cfloat>
#include <climits>
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>

#include "test_array_generator.hpp"

#include "rosidl_runtime_cpp/deprecated_helper_byte.hpp"
#include "rosidl_generator_tests/msg/arrays.hpp"
#include "rosidl_generator_tests/msg/basic_types.hpp"
#include "rosidl_generator_tests/msg/bounded_sequences.hpp"
Expand Down Expand Up @@ -151,6 +153,13 @@ TEST(Test_rosidl_generator_traits, has_bounded_size) {
Message.FieldName = FinalValue; \
ASSERT_EQ(FinalValue, Message.FieldName);

#define TEST_BASIC_TYPE_DEPRECATED_FIELD_ASSIGNMENT(Message, FieldName, InitialValue, FinalValue, \
NewType) \
Message.FieldName = InitialValue; \
ASSERT_EQ(InitialValue, static_cast<NewType>(Message.FieldName)); \
Message.FieldName = FinalValue; \
ASSERT_EQ(FinalValue, static_cast<NewType>(Message.FieldName));

#define TEST_STRING_FIELD_ASSIGNMENT(Message, FieldName, InitialValue, FinalValue) \
Message.FieldName = InitialValue; \
ASSERT_STREQ(InitialValue, Message.FieldName.c_str()); \
Expand All @@ -168,7 +177,8 @@ void test_message_basic_types(rosidl_generator_tests::msg::BasicTypes message)
#ifdef __linux__
#pragma GCC diagnostic pop
#endif
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, byte_value, 0, 255)
TEST_BASIC_TYPE_DEPRECATED_FIELD_ASSIGNMENT(message, byte_value, std::byte{0}, std::byte{255},
std::byte)
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, char_value, 0, UINT8_MAX)
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, float32_value, FLT_MIN, FLT_MAX)
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, float64_value, DBL_MIN, DBL_MAX)
Expand Down Expand Up @@ -211,8 +221,8 @@ void test_message_bounded(rosidl_generator_tests::msg::BoundedSequences message)
message, char_values, unsigned char, SEQUENCE_SIZE, \
0, UINT8_MAX)
TEST_BOUNDED_SEQUENCE_TYPES(
message, byte_values, uint8_t, SEQUENCE_SIZE, \
0, UINT8_MAX)
message, byte_values, std::byte, SEQUENCE_SIZE, \
std::byte{0}, std::byte{UINT8_MAX})
TEST_BOUNDED_SEQUENCE_TYPES(
message, float32_values, float, SEQUENCE_SIZE, \
FLT_MIN, FLT_MAX)
Expand Down Expand Up @@ -277,8 +287,8 @@ void test_message_unbounded(rosidl_generator_tests::msg::UnboundedSequences mess
message, char_values, unsigned char, SEQUENCE_SIZE, \
0, UINT8_MAX)
TEST_UNBOUNDED_SEQUENCE_TYPES(
message, byte_values, uint8_t, SEQUENCE_SIZE, \
0, UINT8_MAX)
message, byte_values, std::byte, SEQUENCE_SIZE, \
std::byte{0}, std::byte{UINT8_MAX})
TEST_UNBOUNDED_SEQUENCE_TYPES(
message, float32_values, float, SEQUENCE_SIZE, \
FLT_MIN, FLT_MAX)
Expand Down Expand Up @@ -331,8 +341,8 @@ void test_message_arrays(rosidl_generator_tests::msg::Arrays message)
message, char_values, unsigned char, ARRAY_SIZE, \
0, UINT8_MAX)
TEST_ARRAY_TYPES(
message, byte_values, uint8_t, ARRAY_SIZE, \
0, UINT8_MAX)
message, byte_values, std::byte, ARRAY_SIZE, \
std::byte{0}, std::byte{UINT8_MAX})
TEST_ARRAY_TYPES(
message, float32_values, float, ARRAY_SIZE, \
FLT_MIN, FLT_MAX)
Expand Down Expand Up @@ -463,7 +473,7 @@ TEST(Test_messages, unbounded_sequence_unbounded) {
TEST(Test_messages, constants) {
rosidl_generator_tests::msg::Constants message;
ASSERT_EQ(true, message.BOOL_CONST);
ASSERT_EQ(50, message.BYTE_CONST);
ASSERT_EQ(std::byte{50}, static_cast<std::byte>(message.BYTE_CONST));
ASSERT_EQ(100, message.CHAR_CONST);
ASSERT_EQ(1.125f, message.FLOAT32_CONST);
ASSERT_EQ(1.125, message.FLOAT64_CONST);
Expand All @@ -487,7 +497,8 @@ TEST(Test_messages, constants_assign) {
TEST(Test_messages, defaults) {
rosidl_generator_tests::msg::Defaults message;
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, bool_value, true, false);
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, byte_value, 50, 255);
TEST_BASIC_TYPE_DEPRECATED_FIELD_ASSIGNMENT(message, byte_value, std::byte{50}, std::byte{255},
std::byte);
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, char_value, 100, UINT8_MAX);
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, float32_value, 1.125f, FLT_MAX);
TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, float64_value, 1.125, DBL_MAX);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ TEST(Test_msg_initialization, build) {
::rosidl_generator_tests::msg::BasicTypes basic =
::rosidl_generator_tests::build<::rosidl_generator_tests::msg::BasicTypes>()
.bool_value(true)
.byte_value(5)
.byte_value(std::byte{5})
.char_value(10)
.float32_value(0.1125f)
.float64_value(0.01125)
Expand All @@ -38,7 +38,7 @@ TEST(Test_msg_initialization, build) {
.uint64_value(5000000ULL);

ASSERT_TRUE(basic.bool_value);
ASSERT_EQ(5, basic.byte_value);
ASSERT_EQ(std::byte{5}, static_cast<std::byte>(basic.byte_value));
ASSERT_EQ(10, basic.char_value);
ASSERT_EQ(0.1125f, basic.float32_value);
ASSERT_EQ(0.01125, basic.float64_value);
Expand All @@ -57,7 +57,7 @@ TEST(Test_msg_initialization, build) {
{
rosidl_generator_tests::build<rosidl_generator_tests::msg::BasicTypes>()
.bool_value(false)
.byte_value(10)
.byte_value(std::byte{10})
.char_value(20)
.float32_value(0.225f)
.float64_value(0.0225)
Expand All @@ -71,7 +71,7 @@ TEST(Test_msg_initialization, build) {
.uint64_value(10000000ULL)});

ASSERT_FALSE(nested.basic_types_value.bool_value);
ASSERT_EQ(10, nested.basic_types_value.byte_value);
ASSERT_EQ(std::byte{10}, static_cast<std::byte>(nested.basic_types_value.byte_value));
ASSERT_EQ(20, nested.basic_types_value.char_value);
ASSERT_EQ(0.225f, nested.basic_types_value.float32_value);
ASSERT_EQ(0.0225, nested.basic_types_value.float64_value);
Expand All @@ -90,7 +90,8 @@ TEST(Test_msg_initialization, build) {
rosidl_generator_tests::msg::Arrays arrays =
rosidl_generator_tests::build<rosidl_generator_tests::msg::Arrays>()
.bool_values({{true, false, true}})
.byte_values({{5, 10, 5}})
.byte_values({{std::byte{5}, std::byte{10}, std::byte{5}}})
// .byte_values({{5, 10, 5}})
.char_values({{10, 20, 10}})
.float32_values({{0.1125f, 0.225f, 0.1125f}})
.float64_values({{0.01125, 0.0225, 0.01125}})
Expand All @@ -107,7 +108,8 @@ TEST(Test_msg_initialization, build) {
.constants_values({{constants, constants, constants}})
.defaults_values({{defaults, defaults, defaults}})
.bool_values_default({{false, true, false}})
.byte_values_default({{10, 5, 10}})
.byte_values_default({{std::byte{10}, std::byte{5}, std::byte{10}}})
// .byte_values_default({{10, 5, 10}})
.char_values_default({{20, 10, 20}})
.float32_values_default({{0.225f, 0.1125f, 0.225f}})
.float64_values_default({{0.0225, 0.01125, 0.0225}})
Expand Down
Loading