diff --git a/rosidl_generator_cpp/resource/idl__struct.hpp.em b/rosidl_generator_cpp/resource/idl__struct.hpp.em index b8f985617..40abd0db3 100644 --- a/rosidl_generator_cpp/resource/idl__struct.hpp.em +++ b/rosidl_generator_cpp/resource/idl__struct.hpp.em @@ -34,6 +34,10 @@ include_directives = set() #include #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" @####################################################################### diff --git a/rosidl_generator_cpp/resource/msg__struct.hpp.em b/rosidl_generator_cpp/resource/msg__struct.hpp.em index 867b8c624..f78ab8623 100644 --- a/rosidl_generator_cpp/resource/msg__struct.hpp.em +++ b/rosidl_generator_cpp/resource/msg__struct.hpp.em @@ -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]; @@ -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(this->@(member.name)) != static_cast(other.@(member.name))) { +@[ else]@ if (this->@(member.name) != other.@(member.name)) { +@[ end if]@ return false; } @[end for]@ diff --git a/rosidl_generator_cpp/resource/msg__traits.hpp.em b/rosidl_generator_cpp/resource/msg__traits.hpp.em index 34e431cd1..7d2654bb0 100644 --- a/rosidl_generator_cpp/resource/msg__traits.hpp.em +++ b/rosidl_generator_cpp/resource/msg__traits.hpp.em @@ -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()) @@ -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(msg.@(member.name)), out); @[ else]@ rosidl_generator_traits::value_to_yaml(msg.@(member.name), out); @[ end if]@ @@ -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(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); @@ -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(msg.@(member.name)), out); @[ else]@ rosidl_generator_traits::value_to_yaml(msg.@(member.name), out); @[ end if]@ @@ -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(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); diff --git a/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py b/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py index a87092274..bca8dba41 100644 --- a/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py +++ b/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py @@ -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 = { @@ -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', @@ -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::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'::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. @@ -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): @@ -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' ]: diff --git a/rosidl_generator_tests/test/rosidl_generator_cpp/test_array_generator.hpp b/rosidl_generator_tests/test/rosidl_generator_cpp/test_array_generator.hpp index 663337b4d..8f3ea5493 100644 --- a/rosidl_generator_tests/test/rosidl_generator_cpp/test_array_generator.hpp +++ b/rosidl_generator_tests/test/rosidl_generator_cpp/test_array_generator.hpp @@ -16,6 +16,8 @@ #define ROSIDL_GENERATOR_CPP__TEST_ARRAY_GENERATOR_HPP_ #include +#include +#include #include #include #include @@ -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::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(max) - std::to_integer(min)) / static_cast(size); + + (*container)[0] = min; + for (size_t i = 1; i < size - 1; i++) { + int val = std::to_integer(min) + i * step; + (*container)[i] = static_cast(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. diff --git a/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp b/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp index 15bb4b7ef..a94dad3ee 100644 --- a/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp +++ b/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp @@ -26,12 +26,14 @@ #include #include #include +#include #include #include #include #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" @@ -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(Message.FieldName)); \ + Message.FieldName = FinalValue; \ + ASSERT_EQ(FinalValue, static_cast(Message.FieldName)); + #define TEST_STRING_FIELD_ASSIGNMENT(Message, FieldName, InitialValue, FinalValue) \ Message.FieldName = InitialValue; \ ASSERT_STREQ(InitialValue, Message.FieldName.c_str()); \ @@ -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) @@ -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) @@ -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) @@ -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) @@ -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(message.BYTE_CONST)); ASSERT_EQ(100, message.CHAR_CONST); ASSERT_EQ(1.125f, message.FLOAT32_CONST); ASSERT_EQ(1.125, message.FLOAT64_CONST); @@ -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); diff --git a/rosidl_generator_tests/test/rosidl_generator_cpp/test_msg_builder.cpp b/rosidl_generator_tests/test/rosidl_generator_cpp/test_msg_builder.cpp index 229668c27..02131ad2a 100644 --- a/rosidl_generator_tests/test/rosidl_generator_cpp/test_msg_builder.cpp +++ b/rosidl_generator_tests/test/rosidl_generator_cpp/test_msg_builder.cpp @@ -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) @@ -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(basic.byte_value)); ASSERT_EQ(10, basic.char_value); ASSERT_EQ(0.1125f, basic.float32_value); ASSERT_EQ(0.01125, basic.float64_value); @@ -57,7 +57,7 @@ TEST(Test_msg_initialization, build) { { rosidl_generator_tests::build() .bool_value(false) - .byte_value(10) + .byte_value(std::byte{10}) .char_value(20) .float32_value(0.225f) .float64_value(0.0225) @@ -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(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); @@ -90,7 +90,8 @@ TEST(Test_msg_initialization, build) { rosidl_generator_tests::msg::Arrays arrays = rosidl_generator_tests::build() .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}}) @@ -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}}) diff --git a/rosidl_generator_tests/test/rosidl_generator_cpp/test_msg_initialization.cpp b/rosidl_generator_tests/test/rosidl_generator_cpp/test_msg_initialization.cpp index 668aed0b0..f128a1572 100644 --- a/rosidl_generator_tests/test/rosidl_generator_cpp/test_msg_initialization.cpp +++ b/rosidl_generator_tests/test/rosidl_generator_cpp/test_msg_initialization.cpp @@ -14,6 +14,7 @@ #include +#include #include #include @@ -47,7 +48,7 @@ make_scope_exit(Callable callable) TEST(Test_msg_initialization, no_arg_constructor) { rosidl_generator_tests::msg::Defaults def; ASSERT_TRUE(def.bool_value); - ASSERT_EQ(50, def.byte_value); + ASSERT_EQ(std::byte{50}, static_cast(def.byte_value)); ASSERT_EQ(100, def.char_value); ASSERT_EQ(1.125f, def.float32_value); ASSERT_EQ(1.125, def.float64_value); @@ -62,7 +63,7 @@ TEST(Test_msg_initialization, no_arg_constructor) { rosidl_generator_tests::msg::BasicTypes basic; ASSERT_FALSE(basic.bool_value); - ASSERT_EQ(0, basic.byte_value); + ASSERT_EQ(std::byte{0}, static_cast(basic.byte_value)); ASSERT_EQ(0, basic.char_value); ASSERT_EQ(0.0f, basic.float32_value); ASSERT_EQ(0.0, basic.float64_value); @@ -79,7 +80,7 @@ TEST(Test_msg_initialization, all_constructor) { rosidl_generator_tests::msg::Defaults def( rosidl_runtime_cpp::MessageInitialization::ALL); ASSERT_TRUE(def.bool_value); - ASSERT_EQ(50, def.byte_value); + ASSERT_EQ(std::byte{50}, static_cast(def.byte_value)); ASSERT_EQ(100, def.char_value); ASSERT_EQ(1.125f, def.float32_value); ASSERT_EQ(1.125, def.float64_value); @@ -94,7 +95,7 @@ TEST(Test_msg_initialization, all_constructor) { rosidl_generator_tests::msg::BasicTypes basic; ASSERT_FALSE(basic.bool_value); - ASSERT_EQ(0, basic.byte_value); + ASSERT_EQ(std::byte{0}, static_cast(basic.byte_value)); ASSERT_EQ(0, basic.char_value); ASSERT_EQ(0.0f, basic.float32_value); ASSERT_EQ(0.0, basic.float64_value); @@ -111,7 +112,7 @@ TEST(Test_msg_initialization, zero_constructor) { rosidl_generator_tests::msg::Defaults def( rosidl_runtime_cpp::MessageInitialization::ZERO); ASSERT_FALSE(def.bool_value); - ASSERT_EQ(0, def.byte_value); + ASSERT_EQ(std::byte{0}, static_cast(def.byte_value)); ASSERT_EQ(0, def.char_value); ASSERT_EQ(0.0f, def.float32_value); ASSERT_EQ(0.0, def.float64_value); @@ -126,7 +127,7 @@ TEST(Test_msg_initialization, zero_constructor) { rosidl_generator_tests::msg::BasicTypes basic; ASSERT_FALSE(basic.bool_value); - ASSERT_EQ(0, basic.byte_value); + ASSERT_EQ(std::byte{0}, static_cast(basic.byte_value)); ASSERT_EQ(0, basic.char_value); ASSERT_EQ(0.0f, basic.float32_value); ASSERT_EQ(0.0, basic.float64_value); @@ -143,7 +144,7 @@ TEST(Test_msg_initialization, defaults_only_constructor) { rosidl_generator_tests::msg::Defaults def( rosidl_runtime_cpp::MessageInitialization::DEFAULTS_ONLY); ASSERT_TRUE(def.bool_value); - ASSERT_EQ(50, def.byte_value); + ASSERT_EQ(std::byte{50}, static_cast(def.byte_value)); ASSERT_EQ(100, def.char_value); ASSERT_EQ(1.125f, def.float32_value); ASSERT_EQ(1.125, def.float64_value); @@ -158,7 +159,7 @@ TEST(Test_msg_initialization, defaults_only_constructor) { rosidl_generator_tests::msg::BasicTypes basic; ASSERT_FALSE(basic.bool_value); - ASSERT_EQ(0, basic.byte_value); + ASSERT_EQ(std::byte{0}, static_cast(basic.byte_value)); ASSERT_EQ(0, basic.char_value); ASSERT_EQ(0.0f, basic.float32_value); ASSERT_EQ(0.0, basic.float64_value); diff --git a/rosidl_generator_tests/test/rosidl_generator_cpp/test_srv_initialization.cpp b/rosidl_generator_tests/test/rosidl_generator_cpp/test_srv_initialization.cpp index f4cbdd366..862c58560 100644 --- a/rosidl_generator_tests/test/rosidl_generator_cpp/test_srv_initialization.cpp +++ b/rosidl_generator_tests/test/rosidl_generator_cpp/test_srv_initialization.cpp @@ -14,6 +14,8 @@ #include +#include + #include "rosidl_generator_tests/srv/basic_types.hpp" #include "rosidl_generator_tests/srv/empty.hpp" @@ -22,7 +24,7 @@ TEST(Test_srv_initialization, no_arg_request_constructor) { rosidl_generator_tests::srv::BasicTypes::Request basic_types; EXPECT_EQ(false, basic_types.bool_value); - EXPECT_EQ(0, basic_types.byte_value); + EXPECT_EQ(std::byte{0}, static_cast(basic_types.byte_value)); EXPECT_EQ(0, basic_types.char_value); EXPECT_EQ(0.0F, basic_types.float32_value); EXPECT_EQ(0.0, basic_types.float64_value); @@ -42,7 +44,7 @@ TEST(Test_srv_initialization, no_arg_response_constructor) { rosidl_generator_tests::srv::BasicTypes::Response basic_types; EXPECT_EQ(false, basic_types.bool_value); - EXPECT_EQ(0, basic_types.byte_value); + EXPECT_EQ(std::byte{0}, static_cast(basic_types.byte_value)); EXPECT_EQ(0, basic_types.char_value); EXPECT_EQ(0.0f, basic_types.float32_value); EXPECT_EQ(0.0, basic_types.float64_value); diff --git a/rosidl_runtime_cpp/CMakeLists.txt b/rosidl_runtime_cpp/CMakeLists.txt index e705e11e2..e64319d45 100644 --- a/rosidl_runtime_cpp/CMakeLists.txt +++ b/rosidl_runtime_cpp/CMakeLists.txt @@ -77,6 +77,26 @@ if(BUILD_TESTING) target_link_libraries(test_bounded_vector ${PROJECT_NAME}) endif() + ament_add_gtest(test_byte_container_mixin test/test_byte_container_mixin.cpp) + if(TARGET test_byte_container_mixin) + target_link_libraries(test_byte_container_mixin ${PROJECT_NAME}) + endif() + + ament_add_gtest(test_byte_conversion_helper test/test_byte_conversion_helper.cpp) + if(TARGET test_byte_conversion_helper) + target_link_libraries(test_byte_conversion_helper ${PROJECT_NAME}) + endif() + + ament_add_gtest(test_deprecated_helper_array test/test_deprecated_helper_array.cpp) + if(TARGET test_deprecated_helper_array) + target_link_libraries(test_deprecated_helper_array ${PROJECT_NAME}) + endif() + + ament_add_gtest(test_deprecated_helper_byte test/test_deprecated_helper_byte.cpp) + if(TARGET test_deprecated_helper_byte) + target_link_libraries(test_deprecated_helper_byte ${PROJECT_NAME}) + endif() + add_performance_test(benchmark_bounded_vector test/benchmark/benchmark_bounded_vector.cpp) if(TARGET benchmark_bounded_vector) target_link_libraries(benchmark_bounded_vector ${PROJECT_NAME}) diff --git a/rosidl_runtime_cpp/include/rosidl_runtime_cpp/byte_container_mixin.hpp b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/byte_container_mixin.hpp new file mode 100644 index 000000000..9f8c8cfa4 --- /dev/null +++ b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/byte_container_mixin.hpp @@ -0,0 +1,286 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ROSIDL_RUNTIME_CPP__BYTE_CONTAINER_MIXIN_HPP_ +#define ROSIDL_RUNTIME_CPP__BYTE_CONTAINER_MIXIN_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include "byte_conversion_helpers.hpp" +#include "deprecated_helper_byte.hpp" + +namespace +{ +template +struct rebind_container; + +// std::vector specialization +template +struct rebind_container, B> +{ + using type = std::vector; +}; + +// std::array specialization +template +struct rebind_container, B> +{ + using type = std::array; +}; + +template +constexpr auto & to_byte_container_ref(Container & c) +{ + using ByteContainer = typename rebind_container::type; + return reinterpret_cast(c); +} + +template +constexpr auto & to_uchar_container_ref(Container & c) +{ + using UCharContainer = typename rebind_container::type; + return reinterpret_cast(c); +} +} // namespace + + +namespace rosidl_runtime_cpp +{ + +// Functions shared between std::array and std::vector +template +struct ByteContainerMixin : Container +{ + static_assert(std::is_same_v, + "ByteContainerMixin requires a container of std::byte"); + + + // Override Defaults to match old types + using value_type = unsigned char; + using reference = value_type &; + using const_reference = const reference; + using pointer = value_type *; + using const_pointer = const pointer; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using reverse_const_iterator = std::reverse_iterator; + + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using container_type = Container; + using UCharContainer = typename rebind_container::type; + + // Member Functions + // Constructor + using Container::Container; + + [[deprecated("Use std::array instead of unsigned char array")]] + constexpr ByteContainerMixin(const UCharContainer & arr) noexcept // NOLINT(runtime/explicit) + { + for (std::size_t i = 0; i < Container::size(); ++i) { + Container::at(i) = std::byte{arr[i]}; + } + } + + [[deprecated("Use initializer_list of bytes instead of unsigned chars")]] + constexpr ByteContainerMixin( + std::initializer_list init) // NOLINT(runtime/explicit) + { + std::transform(init.begin(), init.end(), Container::begin(), + [](unsigned char v) {return std::byte{v};}); + } + + constexpr ByteContainerMixin( + std::initializer_list init) // NOLINT(runtime/explicit) + { + std::copy(init.begin(), init.end(), Container::begin()); + } + + // Assignment + using Container::operator=; + + [[deprecated("Use Container of std::byte instead")]] + constexpr UCharContainer & operator=(const UCharContainer & arr) noexcept + { + for (std::size_t i = 0; i < Container::size(); ++i) { + Container::operator[](i) = std::byte{arr[i]}; + } + return to_uchar_container_ref(*this); + } + + constexpr ByteContainerMixin & operator=(std::initializer_list init) noexcept + { + std::copy(init.begin(), init.end(), Container::begin()); + return *this; + } + + [[deprecated("Use initializer_list instead of unsigned chars")]] + constexpr ByteContainerMixin & operator=(std::initializer_list init) noexcept + { + std::transform(init.begin(), init.end(), Container::begin(), + [](unsigned char v) {return std::byte{v};}); + return *this; + } + + // Implicitly-defined Member Functions + + // Element Access + + // at + constexpr detail::ByteRef at(std::size_t pos) + { + return detail::ByteRef{Container::at(pos)}; + } + + constexpr DeprecatedHelperByte at(std::size_t pos) const + { + return DeprecatedHelperByte{Container::at(pos)}; + } + + // operator[] + constexpr detail::ByteRef operator[](std::size_t pos) + { + return detail::ByteRef{Container::operator[](pos)}; + } + + constexpr DeprecatedHelperByte operator[](std::size_t pos) const + { + return DeprecatedHelperByte{Container::operator[](pos)}; + } + + // front + constexpr detail::ByteRef front() + { + return detail::ByteRef{Container::front()}; + } + + constexpr DeprecatedHelperByte front() const + { + return DeprecatedHelperByte{Container::front()}; + } + + // back + constexpr detail::ByteRef back() + { + return detail::ByteRef{Container::back()}; + } + + constexpr DeprecatedHelperByte back() const + { + return DeprecatedHelperByte{Container::back()}; + } + + // data() + constexpr detail::BytePtr data() + { + return detail::BytePtr{Container::data()}; + } + + constexpr detail::ConstBytePtr data() const + { + return detail::ConstBytePtr{Container::data()}; + } + + // Iterators + + // begin, cbegin + constexpr detail::BytePtr begin() noexcept + { + return detail::BytePtr{Container::begin()}; + } + + constexpr detail::ConstBytePtr begin() const noexcept + { + return detail::ConstBytePtr{Container::begin()}; + } + + constexpr detail::ConstBytePtr cbegin() const noexcept + { + return detail::ConstBytePtr{Container::cbegin()}; + } + + // end, cend + constexpr detail::BytePtr end() noexcept + { + return detail::BytePtr{Container::end()}; + } + + constexpr detail::ConstBytePtr end() const noexcept + { + return detail::ConstBytePtr{Container::end()}; + } + + constexpr detail::ConstBytePtr cend() const noexcept + { + return detail::ConstBytePtr{Container::cend()}; + } + + // rbegin, crbegin + constexpr detail::BytePtr rbegin() noexcept + { + return detail::BytePtr{Container::rbegin()}; + } + + constexpr detail::ConstBytePtr rbegin() const noexcept + { + return detail::ConstBytePtr{Container::rbegin()}; + } + + constexpr detail::ConstBytePtr crbegin() const noexcept + { + return detail::ConstBytePtr{Container::crbegin()}; + } + + // rend, crend + constexpr detail::BytePtr rend() noexcept + { + return detail::BytePtr{Container::rend()}; + } + + constexpr detail::ConstBytePtr rend() const noexcept + { + return detail::ConstBytePtr{Container::rend()}; + } + + constexpr detail::ConstBytePtr crend() const noexcept + { + return detail::ConstBytePtr{Container::crend()}; + } + + // Getter + [[deprecated("Convert to container of std::byte instead")]] + constexpr operator UCharContainer &() noexcept + { + return to_uchar_container_ref(*this); + } + + // Operations + [[deprecated("Switch to calling swap with container of std::byte")]] + constexpr void swap(UCharContainer & other) + { + Container::swap(to_byte_container_ref(other)); + } +}; +} // namespace rosidl_runtime_cpp + +#endif // ROSIDL_RUNTIME_CPP__BYTE_CONTAINER_MIXIN_HPP_ diff --git a/rosidl_runtime_cpp/include/rosidl_runtime_cpp/byte_conversion_helpers.hpp b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/byte_conversion_helpers.hpp new file mode 100644 index 000000000..508575d39 --- /dev/null +++ b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/byte_conversion_helpers.hpp @@ -0,0 +1,166 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ROSIDL_RUNTIME_CPP__BYTE_CONVERSION_HELPERS_HPP_ +#define ROSIDL_RUNTIME_CPP__BYTE_CONVERSION_HELPERS_HPP_ + +#include + +namespace rosidl_runtime_cpp +{ + +namespace detail +{ + +struct ByteRef +{ + constexpr ByteRef(std::byte & b) // NOLINT(runtime/explicit) + : ref(b) {} + + // TODO(invinciblermc) + // Make constexpr bit_cast in C++20 + [[deprecated("Assign a std::byte &")]] + ByteRef(unsigned char & b) // NOLINT(runtime/explicit) + : ref(reinterpret_cast(b)) {} + + // = + constexpr ByteRef & operator=(std::byte b) + { + ref = b; + return *this; + } + + [[deprecated("Assign to with std::byte")]] + constexpr ByteRef & operator=(unsigned char c) + { + ref = std::byte{c}; + return *this; + } + + explicit constexpr operator std::byte() const + { + return ref; + } + + [[deprecated("Return a std::byte")]] + constexpr operator unsigned char() const + { + return std::to_integer(ref); + } + +private: + std::byte & ref; +}; + +struct ConstByteRef +{ + constexpr ConstByteRef(const std::byte & b) noexcept // NOLINT(runtime/explicit) + : ref(b) {} + + // TODO(invinciblermc) + // Make constexpr bit_cast in C++20 + [[deprecated("Assign a const std::byte &")]] + ConstByteRef(const unsigned char & b) noexcept // NOLINT(runtime/explicit) + : ref(reinterpret_cast(b)) {} + + // Conversion to std::byte + explicit constexpr operator std::byte() const noexcept + { + return ref; + } + + // Conversion to unsigned char + [[deprecated("Use static_cast instead")]] + constexpr operator unsigned char() const noexcept + { + return std::to_integer(ref); + } + +private: + const std::byte & ref; +}; + +struct BytePtr +{ + constexpr BytePtr(std::byte * p) // NOLINT(runtime/explicit) + : ptr(p) {} + + // TODO(invinciblermc) + // Make constexpr bit_cast in C++20 + [[deprecated("Construct with std::byte *")]] + BytePtr(unsigned char * p) // NOLINT(runtime/explicit) + : ptr(reinterpret_cast(p)) {} + + constexpr ByteRef operator*() const + { + return ByteRef{*ptr}; + } + + constexpr ByteRef operator[](std::size_t i) const + { + return ByteRef{ptr[i]}; + } + + // Pointer math + constexpr BytePtr & operator++() {++ptr; return *this;} + constexpr BytePtr operator++(int) {BytePtr tmp = *this; ++(*this); return tmp;} + constexpr BytePtr & operator--() {--ptr; return *this;} + constexpr BytePtr operator--(int) {BytePtr tmp = *this; --(*this); return tmp;} + + // * + explicit constexpr operator std::byte *() const {return ptr;} + + // TODO(invinciblermc) + // Make constexpr bit_cast in C++20 + [[deprecated("static_cast(arr)")]] + operator unsigned char *() const {return reinterpret_cast(ptr);} + +private: + std::byte * ptr; +}; + +struct ConstBytePtr +{ + constexpr ConstBytePtr(const std::byte * p) // NOLINT(runtime/explicit) + : ptr(p) {} + + // TODO(invinciblermc) + // Make constexpr bit_cast in C++20 + [[deprecated("Assign a const std::byte *")]] + ConstBytePtr(const unsigned char * p) // NOLINT(runtime/explicit) + : ptr(reinterpret_cast(p)) {} + + constexpr ConstByteRef operator*() const {return ConstByteRef{*ptr};} + constexpr ConstByteRef operator[](std::size_t i) const {return ConstByteRef{ptr[i]};} + + constexpr ConstBytePtr & operator++() {++ptr; return *this;} + constexpr ConstBytePtr operator++(int) {ConstBytePtr tmp = *this; ++(*this); return tmp;} + constexpr ConstBytePtr & operator--() {--ptr; return *this;} + constexpr ConstBytePtr operator--(int) {ConstBytePtr tmp = *this; --(*this); return tmp;} + + explicit constexpr operator const std::byte *() const {return ptr;} + + // TODO(invinciblermc) + // Make constexpr bit_cast in C++20 + [[deprecated("static_cast(arr)")]] + operator const unsigned char *() const {return reinterpret_cast(ptr);} + +private: + const std::byte * ptr; +}; + +} // namespace detail +} // namespace rosidl_runtime_cpp + +#endif // ROSIDL_RUNTIME_CPP__BYTE_CONVERSION_HELPERS_HPP_ diff --git a/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_array.hpp b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_array.hpp new file mode 100644 index 000000000..a8fff74b4 --- /dev/null +++ b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_array.hpp @@ -0,0 +1,275 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_ARRAY_HPP_ +#define ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_ARRAY_HPP_ + +#include +#include +#include +#include +#include + +#include "byte_conversion_helpers.hpp" +#include "byte_container_mixin.hpp" + + +// Anonymous namespace for private Helpers +namespace +{ +template +constexpr std::array to_byte_array(const std::array & arr) +{ + std::array byte_array{}; + + for (std::size_t i = 0; i < N; i++) { + byte_array[i] = std::byte{arr[i]}; + } + return byte_array; +} +} // namespace + + +namespace rosidl_runtime_cpp +{ + +template +struct DeprecatedHelperArray : ByteContainerMixin> +{ + using Mixin = ByteContainerMixin>; + using Mixin::value_type; + using Mixin::reference; + using Mixin::const_reference; + using Mixin::pointer; + using Mixin::const_pointer; + using Mixin::iterator; + using Mixin::const_iterator; + using Mixin::reverse_iterator; + using Mixin::reverse_const_iterator; + + // Helper Types + using ByteArray = std::array; + using UCharArray = std::array; + + // Implicitly-defined member functions + + // Suppress warning about inherited deprecated Constructor + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + using Mixin::Mixin; + + #pragma GCC diagnostic pop + using Mixin::operator=; + + // Element Access + using Mixin::at; + using Mixin::operator[]; + using Mixin::front; + using Mixin::back; + using Mixin::data; + + // Iterators + using Mixin::begin; + using Mixin::cbegin; + using Mixin::end; + using Mixin::cend; + using Mixin::rbegin; + using Mixin::crbegin; + using Mixin::rend; + using Mixin::crend; + + // Capacity + using Mixin::empty; + using Mixin::size; + using Mixin::max_size; + + // Getter + using Mixin::operator UCharArray &; + + // Operations + using ByteArray::fill; + + [[deprecated("Switch to calling fill with std::byte")]] + constexpr void fill(const unsigned char & value) + { + ByteArray::fill(std::byte{value}); + } + + using Mixin::swap; +}; + +// == +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator==( + const std::array & lhs, + const DeprecatedHelperArray & rhs) +{ + return to_byte_array(lhs) == rhs; +} + +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator==( + const DeprecatedHelperArray & lhs, + const std::array & rhs) +{ + return lhs == to_byte_array(rhs); +} + +// != +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator!=( + const std::array & lhs, + const DeprecatedHelperArray & rhs) +{ + return to_byte_array(lhs) != rhs; +} + +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator!=( + const DeprecatedHelperArray & lhs, + const std::array & rhs) +{ + return lhs != to_byte_array(rhs); +} + +// < +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator<( + const std::array & lhs, + const DeprecatedHelperArray & rhs) +{ + return to_byte_array(lhs) < rhs; +} + +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator<( + const DeprecatedHelperArray & lhs, + const std::array & rhs) +{ + return lhs < to_byte_array(rhs); +} + +// <= +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator<=( + const std::array & lhs, + const DeprecatedHelperArray & rhs) +{ + return to_byte_array(lhs) <= rhs; +} + +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator<=( + const DeprecatedHelperArray & lhs, + const std::array & rhs) +{ + return lhs <= to_byte_array(rhs); +} + +// > +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator>( + const std::array & lhs, + const DeprecatedHelperArray & rhs) +{ + return to_byte_array(lhs) > rhs; +} + +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator>( + const DeprecatedHelperArray & lhs, + const std::array & rhs) +{ + return lhs > to_byte_array(rhs); +} + +// >= +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator>=( + const std::array & lhs, + const DeprecatedHelperArray & rhs) +{ + return to_byte_array(lhs) >= rhs; +} + +template +[[deprecated("Do comparisons with std::array")]] +constexpr bool operator>=( + const DeprecatedHelperArray & lhs, + const std::array & rhs) +{ + return lhs >= to_byte_array(rhs); +} + +} // namespace rosidl_runtime_cpp + +namespace std +{ + +// Non-member Functions + +template +constexpr rosidl_runtime_cpp::detail::ByteRef +get(rosidl_runtime_cpp::DeprecatedHelperArray & arr) noexcept +{ + static_assert(I < N, "Index out of range for DeprecatedHelperArray"); + return rosidl_runtime_cpp::detail::ByteRef{arr[I]}; +} + +template +constexpr rosidl_runtime_cpp::detail::ConstByteRef +get(const rosidl_runtime_cpp::DeprecatedHelperArray & arr) noexcept +{ + static_assert(I < N, "Index out of range for DeprecatedHelperArray"); + return rosidl_runtime_cpp::detail::ConstByteRef{arr[I]}; +} + +template +constexpr rosidl_runtime_cpp::detail::ByteRef +get(rosidl_runtime_cpp::DeprecatedHelperArray && arr) noexcept +{ + static_assert(I < N, "Index out of range for DeprecatedHelperArray"); + return rosidl_runtime_cpp::detail::ByteRef{arr[I]}; +} + +template +constexpr rosidl_runtime_cpp::detail::ConstByteRef +get(const rosidl_runtime_cpp::DeprecatedHelperArray && arr) noexcept +{ + static_assert(I < N, "Index out of range for DeprecatedHelperArray"); + return rosidl_runtime_cpp::detail::ConstByteRef{arr[I]}; +} + +// tuple_element +template +struct tuple_element> +{ + static_assert(I < N, "Index out of range for DeprecatedHelperArray"); + using type = unsigned char; +}; +} // namespace std + +#endif // ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_ARRAY_HPP_ diff --git a/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_bounded_vector.hpp b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_bounded_vector.hpp new file mode 100644 index 000000000..55602bfcd --- /dev/null +++ b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_bounded_vector.hpp @@ -0,0 +1,207 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_BOUNDED_VECTOR_HPP_ +#define ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_BOUNDED_VECTOR_HPP_ + +#include +#include +#include + +#include "byte_conversion_helpers.hpp" +#include "bounded_vector.hpp" + +namespace rosidl_runtime_cpp +{ +template> +struct DeprecatedHelperBoundedVector : BoundedVector +{ + // // Override Defaults to match old types + // using value_type = unsigned char; + // using allocator_type = std::allocator; + // using reference = value_type &; + // using const_reference = const reference; + // using pointer = value_type *; + // using const_pointer = const pointer; + // using iterator = pointer; + // using const_iterator = const_pointer; + // using reverse_iterator = std::reverse_iterator; + // using reverse_const_iterator = std::reverse_iterator; + + // // Helper Types + // using ByteVector = BoundedVector; + // using UCharVector = BoundedVector; + + + // // Member functions + // using ByteVector::ByteVector; + // using ByteVector::operator=; + // using ByteVector::assign; + + // // Element Access + // using ByteVector::at; + // using ByteVector::operator[]; + // using ByteVector::front; + // using ByteVector::back; + // using ByteVector::data; + + // // Iterators + // using ByteVector::begin; + // using ByteVector::cbegin; + // using ByteVector::end; + // using ByteVector::cend; + // using ByteVector::rbegin; + // using ByteVector::crbegin; + // using ByteVector::rend; + // using ByteVector::crend; + + // // Capacity + // using ByteVector::empty; + // using ByteVector::size; + // using ByteVector::max_size; + // using ByteVector::reserve; + // using ByteVector::capacity; + // using ByteVector::shrink_to_fit; + + // // Modifiers + // using ByteVector::clear; + // using ByteVector::insert; + // using ByteVector::emplace; + // using ByteVector::erase; + // using ByteVector::push_back; + // using ByteVector::emplace_back; + // using ByteVector::pop_back; + // using ByteVector::resize; + // using ByteVector::swap; +}; + +// // == +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator==( +// const std::array & lhs, +// const DeprecatedHelperArray & rhs) +// { +// return to_byte_array(lhs) == rhs; +// } + +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator==( +// const DeprecatedHelperArray & lhs, +// const std::array & rhs) +// { +// return lhs == to_byte_array(rhs); +// } + +// // != +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator!=( +// const std::array & lhs, +// const DeprecatedHelperArray & rhs) +// { +// return to_byte_array(lhs) != rhs; +// } + +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator!=( +// const DeprecatedHelperArray & lhs, +// const std::array & rhs) +// { +// return lhs != to_byte_array(rhs); +// } + +// // < +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator<( +// const std::array & lhs, +// const DeprecatedHelperArray & rhs) +// { +// return to_byte_array(lhs) < rhs; +// } + +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator<( +// const DeprecatedHelperArray & lhs, +// const std::array & rhs) +// { +// return lhs < to_byte_array(rhs); +// } + +// // <= +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator<=( +// const std::array & lhs, +// const DeprecatedHelperArray & rhs) +// { +// return to_byte_array(lhs) <= rhs; +// } + +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator<=( +// const DeprecatedHelperArray & lhs, +// const std::array & rhs) +// { +// return lhs <= to_byte_array(rhs); +// } + +// // > +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator>( +// const std::array & lhs, +// const DeprecatedHelperArray & rhs) +// { +// return to_byte_array(lhs) > rhs; +// } + +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator>( +// const DeprecatedHelperArray & lhs, +// const std::array & rhs) +// { +// return lhs > to_byte_array(rhs); +// } + +// // >= +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator>=( +// const std::array & lhs, +// const DeprecatedHelperArray & rhs) +// { +// return to_byte_array(lhs) >= rhs; +// } + +// template +// [[deprecated("Do comparisons with std::array")]] +// constexpr bool operator>=( +// const DeprecatedHelperArray & lhs, +// const std::array & rhs) +// { +// return lhs >= to_byte_array(rhs); +// } + +} // namespace rosidl_runtime_cpp + +// Non-member Function + +#endif // ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_BOUNDED_VECTOR_HPP_ diff --git a/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_byte.hpp b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_byte.hpp new file mode 100644 index 000000000..0e273dbcf --- /dev/null +++ b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_byte.hpp @@ -0,0 +1,70 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_BYTE_HPP_ +#define ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_BYTE_HPP_ + +#include +#include +#include + +namespace rosidl_runtime_cpp +{ +struct DeprecatedHelperByte +{ + // Constructor + constexpr DeprecatedHelperByte() noexcept = default; + + [[deprecated("Initialize with std::byte instead")]] + constexpr DeprecatedHelperByte(unsigned char value) noexcept // NOLINT(runtime/explicit) + : b(std::byte{value}) {} + + constexpr DeprecatedHelperByte(std::byte value) noexcept // NOLINT(runtime/explicit) + : b(value) {} + + // Getter + + // TODO(invinciblermc) + // Make constexpr bit_cast in C++20 + [[deprecated("Use static_cast instead")]] + operator unsigned char &() noexcept + { + return *reinterpret_cast(&b); + } + + // Used for comparisons with const int + [[deprecated("Use static_cast instead")]] + constexpr operator unsigned char() const noexcept + { + return std::to_integer(b); + } + + // To avoid collisions with unsigned char + // Explicit needing a static_cast<> until unsigned char is removed. + explicit constexpr operator std::byte & () noexcept + { + return b; + } + + explicit constexpr operator std::byte() const noexcept + { + return b; + } + +private: + std::byte b{}; +}; +} // namespace rosidl_runtime_cpp + +#endif // ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_BYTE_HPP_ diff --git a/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_vector.hpp b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_vector.hpp new file mode 100644 index 000000000..eed9260a8 --- /dev/null +++ b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/deprecated_helper_vector.hpp @@ -0,0 +1,37 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_VECTOR_HPP_ +#define ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_VECTOR_HPP_ + +#include +#include +#include +#include +#include + + +namespace rosidl_runtime_cpp +{ +// using T = unsigned char; +// using T = std::byte; +// template> +// using DeprecatedHelperVector = std::vector; + +template> +struct DeprecatedHelperVector : std::vector +{}; +} // namespace rosidl_runtime_cpp + +#endif // ROSIDL_RUNTIME_CPP__DEPRECATED_HELPER_VECTOR_HPP_ diff --git a/rosidl_runtime_cpp/include/rosidl_runtime_cpp/traits.hpp b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/traits.hpp index 5a4773c66..a7b240bf0 100644 --- a/rosidl_runtime_cpp/include/rosidl_runtime_cpp/traits.hpp +++ b/rosidl_runtime_cpp/include/rosidl_runtime_cpp/traits.hpp @@ -16,6 +16,7 @@ #define ROSIDL_RUNTIME_CPP__TRAITS_HPP_ #include +#include #include #include #include @@ -38,11 +39,11 @@ inline void character_value_to_yaml(unsigned char value, std::ostream & out) out.flags(flags); } -inline void character_value_to_yaml(char16_t value, std::ostream & out) +inline void value_to_yaml(std::byte value, std::ostream & out) { auto flags = out.flags(); - out << "\"\\u" << std::hex << std::setw(4) << std::setfill('0') << \ - static_cast(value) << "\""; + out << "0x" << std::hex << std::setw(2) << std::setfill('0') << \ + std::to_integer(value); out.flags(flags); } diff --git a/rosidl_runtime_cpp/test/test_byte_container_mixin.cpp b/rosidl_runtime_cpp/test/test_byte_container_mixin.cpp new file mode 100644 index 000000000..6c5ef4ead --- /dev/null +++ b/rosidl_runtime_cpp/test/test_byte_container_mixin.cpp @@ -0,0 +1,197 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include + +#include "rosidl_runtime_cpp/deprecated_helper_array.hpp" + + +// Suppress deprecation notices to allow unit testing of deprecated functions. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + +TEST(rosidl_generator_cpp, deprecated_helper_array_constructor) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{}; + std::array empty_byte_array{}; + std::array empty_uchar_array{}; + + ASSERT_EQ(dep_array, empty_byte_array); + ASSERT_EQ(dep_array, empty_uchar_array); + + std::array byte_array = {std::byte{6}, std::byte{1}, std::byte{11}}; + std::array char_array = {6, 1, 11}; + + dep_array = byte_array; + EXPECT_EQ(dep_array, byte_array); + EXPECT_EQ(dep_array, char_array); + + // Clear + dep_array = {0, 0, 0}; + dep_array = char_array; + EXPECT_EQ(dep_array, byte_array); + EXPECT_EQ(dep_array, char_array); + + std::array byte_array2 = {std::byte{1}, std::byte{2}, std::byte{3}}; + std::array char_array2 = {1, 2, 3}; + + dep_array = {std::byte{1}, std::byte{2}, std::byte{3}}; + EXPECT_EQ(dep_array, byte_array2); + EXPECT_EQ(dep_array, char_array2); + + dep_array = {0, 0, 0}; + dep_array = {1, 2, 3}; + EXPECT_EQ(dep_array, byte_array2); + EXPECT_EQ(dep_array, char_array2); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_operator_index) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{}; + dep_array.fill(std::byte{5}); + EXPECT_EQ(static_cast(dep_array[0]), std::byte{5}); + EXPECT_EQ(static_cast(dep_array[1]), std::byte{5}); + EXPECT_EQ(static_cast(dep_array[2]), std::byte{5}); + + dep_array[0] = 10; + dep_array[1] = std::byte{10}; + dep_array[2] = 10; + EXPECT_EQ(static_cast(dep_array[0]), std::byte{10}); + EXPECT_EQ(static_cast(dep_array[1]), std::byte{10}); + EXPECT_EQ(dep_array[0], 10); + EXPECT_EQ(dep_array[1], 10); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_at) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{}; + dep_array.fill(std::byte{7}); + + EXPECT_EQ(static_cast(dep_array.at(0)), std::byte{7}); + EXPECT_EQ(dep_array.at(2), 7); + + dep_array.at(1) = 11; + EXPECT_EQ(static_cast(dep_array.at(1)), std::byte{11}); + EXPECT_THROW(dep_array.at(3), std::out_of_range); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_data) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{}; + dep_array.fill(std::byte{9}); + + auto data_ptr = dep_array.data(); + EXPECT_EQ(static_cast(*data_ptr), std::byte{9}); + + data_ptr[2] = std::byte{15}; + EXPECT_EQ(static_cast(dep_array[2]), std::byte{15}); + + unsigned char * char_data_ptr = dep_array.data(); + char_data_ptr[1] = 10; + + auto byte_data_ptr = static_cast(dep_array.data()); + byte_data_ptr[0] = std::byte{3}; + EXPECT_EQ(char_data_ptr[0], 3); + EXPECT_EQ(char_data_ptr[1], 10); + EXPECT_EQ(char_data_ptr[2], 15); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_begin_end) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{}; + dep_array.fill(std::byte{3}); + + auto it = dep_array.begin(); + auto end_it = dep_array.end(); + + EXPECT_NE(it, end_it); + EXPECT_EQ(static_cast(*it), std::byte{3}); + + int count = 0; + for (auto iter = dep_array.begin(); iter != dep_array.end(); ++iter) { + EXPECT_EQ(static_cast(*iter), std::byte{3}); + ++count; + } + EXPECT_EQ(count, 3); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_cbegin_cend) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{}; + dep_array.fill(std::byte{4}); + + auto cit = dep_array.cbegin(); + auto cend_it = dep_array.cend(); + + EXPECT_NE(cit, cend_it); + EXPECT_EQ(static_cast(*cit), std::byte{4}); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_empty) { + rosidl_runtime_cpp::DeprecatedHelperArray<0> empty_array{}; + rosidl_runtime_cpp::DeprecatedHelperArray<3> non_empty_array{}; + + EXPECT_TRUE(empty_array.empty()); + EXPECT_FALSE(non_empty_array.empty()); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_front_back) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{}; + dep_array[0] = std::byte{7}; + dep_array[1] = std::byte{8}; + dep_array[2] = std::byte{9}; + + EXPECT_EQ(static_cast(dep_array.front()), std::byte{7}); + EXPECT_EQ(static_cast(dep_array.back()), std::byte{9}); + + dep_array.front() = std::byte{10}; + dep_array.back() = std::byte{11}; + + EXPECT_EQ(static_cast(dep_array[0]), std::byte{10}); + EXPECT_EQ(static_cast(dep_array[2]), std::byte{11}); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_swap) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array1{}; + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array2{}; + + dep_array1 = {std::byte{1}, std::byte{2}, std::byte{3}}; + dep_array2 = {std::byte{4}, std::byte{5}, std::byte{6}}; + + dep_array1.swap(dep_array2); + + EXPECT_EQ(dep_array1, (std::array{std::byte{4}, std::byte{5}, std::byte{6}})); + EXPECT_EQ(dep_array2, (std::array{std::byte{1}, std::byte{2}, std::byte{3}})); +} + + +TEST(rosidl_generator_cpp, deprecated_helper_array_size) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array; + EXPECT_EQ(dep_array.size(), 3); +} + +TEST(rosidl_generator_cpp, deprecated_helper_convert) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{1, 2, 3}; + std::array byte_array = dep_array; + std::array uchar_array = dep_array; + + EXPECT_EQ(byte_array, dep_array); + EXPECT_EQ(uchar_array, dep_array); +} + + +TEST(rosidl_generator_cpp, deprecated_helper_array_function) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array{1, 2, 3}; +} + +#pragma GCC diagnostic pop diff --git a/rosidl_runtime_cpp/test/test_byte_conversion_helper.cpp b/rosidl_runtime_cpp/test/test_byte_conversion_helper.cpp new file mode 100644 index 000000000..f9807b77e --- /dev/null +++ b/rosidl_runtime_cpp/test/test_byte_conversion_helper.cpp @@ -0,0 +1,114 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "rosidl_runtime_cpp/byte_conversion_helpers.hpp" + + +// Suppress deprecation notices to allow unit testing of deprecated functions. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + +TEST(rosidl_generator_cpp, byte_ref) { + std::byte b{10}; + + rosidl_runtime_cpp::detail::ByteRef byte_ref{b}; + + byte_ref = 3; + + ASSERT_EQ(byte_ref, 3); + ASSERT_EQ(static_cast(byte_ref), std::byte{3}); + + byte_ref = std::byte{4}; + + ASSERT_EQ(byte_ref, 4); + ASSERT_EQ(static_cast(byte_ref), std::byte{4}); + + std::byte bb = static_cast(byte_ref); + unsigned char uchar = byte_ref; + + ASSERT_EQ(bb, std::byte{4}); + ASSERT_EQ(uchar, 4); +} + +TEST(rosidl_generator_cpp, const_byte_ref) { + const std::byte b{5}; + rosidl_runtime_cpp::detail::ConstByteRef const_ref{b}; + + EXPECT_EQ(const_ref, 5); + EXPECT_EQ(static_cast(const_ref), std::byte{5}); + + std::byte bb = static_cast(const_ref); + unsigned char uchar = const_ref; + + EXPECT_EQ(bb, std::byte{5}); + EXPECT_EQ(uchar, 5); +} + +TEST(rosidl_generator_cpp, byte_ptr) { + std::byte b{42}; + rosidl_runtime_cpp::detail::BytePtr byte_ptr{&b}; + + EXPECT_EQ(*byte_ptr, 42); + + *byte_ptr = std::byte{99}; + EXPECT_EQ(b, std::byte{99}); + + std::byte byte_2{25}; + byte_ptr = &byte_2; + EXPECT_EQ(*byte_ptr, 25); + EXPECT_EQ(static_cast(*byte_ptr), std::byte{25}); + + unsigned char uchar2 = 13; + byte_ptr = &uchar2; + EXPECT_EQ(*byte_ptr, 13); + EXPECT_EQ(static_cast(*byte_ptr), std::byte{13}); + + *byte_ptr = 100; + EXPECT_EQ(*byte_ptr, 100); + EXPECT_EQ(uchar2, 100); + + std::byte bb = static_cast(*byte_ptr); + EXPECT_EQ(bb, std::byte{100}); + + unsigned char uchar = *byte_ptr; + EXPECT_EQ(uchar, 100); + + std::byte foo{25}; + std::byte *bstar = &foo; + byte_ptr = bstar; + EXPECT_EQ(static_cast(byte_ptr), bstar); + + unsigned char uchar3 = 25; + unsigned char *ustar = &uchar3; + byte_ptr = ustar; + EXPECT_EQ(byte_ptr, ustar); +} + +TEST(rosidl_generator_cpp, const_byte_ptr) { + const std::byte b{200}; + rosidl_runtime_cpp::detail::ConstBytePtr const_byte_ptr{&b}; + EXPECT_EQ(*const_byte_ptr, 200); + EXPECT_EQ(static_cast(*const_byte_ptr), std::byte{200}); + + std::byte bb = static_cast(*const_byte_ptr); + EXPECT_EQ(bb, std::byte{200}); + + unsigned char uchar = *const_byte_ptr; + EXPECT_EQ(uchar, 200); +} + +#pragma GCC diagnostic pop diff --git a/rosidl_runtime_cpp/test/test_deprecated_helper_array.cpp b/rosidl_runtime_cpp/test/test_deprecated_helper_array.cpp new file mode 100644 index 000000000..ede9b8506 --- /dev/null +++ b/rosidl_runtime_cpp/test/test_deprecated_helper_array.cpp @@ -0,0 +1,54 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include +#include + +#include "rosidl_runtime_cpp/deprecated_helper_array.hpp" + + +// Suppress deprecation notices to allow unit testing of deprecated functions. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + +TEST(rosidl_generator_cpp, deprecated_helper_array_fill) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array; + std::array byte_array = {std::byte{10}, std::byte{10}, std::byte{10}}; + std::array char_array = {10, 10, 10}; + dep_array.fill(std::byte{10}); + EXPECT_EQ(dep_array, byte_array); + EXPECT_EQ(dep_array, char_array); + + dep_array.fill(35); + byte_array.fill(std::byte{35}); + char_array.fill(35); + + EXPECT_EQ(dep_array, byte_array); + EXPECT_EQ(dep_array, char_array); +} + +TEST(rosidl_generator_cpp, deprecated_helper_array_tuple_element) { + rosidl_runtime_cpp::DeprecatedHelperArray<3> dep_array; + using T = std::tuple_element<0, decltype(dep_array)>::type; + static_assert(std::is_same_v); + + using B = std::tuple_element<0, std::array>::type; + static_assert(std::is_same_v); +} + +#pragma GCC diagnostic pop diff --git a/rosidl_runtime_cpp/test/test_deprecated_helper_byte.cpp b/rosidl_runtime_cpp/test/test_deprecated_helper_byte.cpp new file mode 100644 index 000000000..ea00d341b --- /dev/null +++ b/rosidl_runtime_cpp/test/test_deprecated_helper_byte.cpp @@ -0,0 +1,94 @@ +// Copyright 2025 Open Source Robotics Foundation, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "rosidl_runtime_cpp/deprecated_helper_byte.hpp" + + +// Suppress deprecation notices to allow unit testing of deprecated functions. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + +TEST(rosidl_generator_cpp, deprecated_helper_byte_getter_setter) { + rosidl_runtime_cpp::DeprecatedHelperByte v; + + v = std::byte{1}; + ASSERT_EQ(static_cast(v), std::byte{1}); + ASSERT_EQ(v, 1); + v = 3; + ASSERT_EQ(static_cast(v), std::byte{3}); + ASSERT_EQ(v, 3); + + v = std::byte{10}; + unsigned char c = v; + ASSERT_EQ(c, 10); + + std::byte d = static_cast(v); + ASSERT_EQ(d, std::byte{10}); + + auto e = v; + ASSERT_EQ(e, 10); +} + +TEST(rosidl_generator_cpp, deprecated_helper_byte_equal) { + rosidl_runtime_cpp::DeprecatedHelperByte f = 10; + rosidl_runtime_cpp::DeprecatedHelperByte g = std::byte{10}; + ASSERT_EQ(10, f); + ASSERT_EQ(f, 10); + ASSERT_EQ(std::byte{10}, static_cast(g)); + ASSERT_EQ(static_cast(g), std::byte{10}); + ASSERT_EQ(f, g); +} + +TEST(rosidl_generator_cpp, deprecated_helper_byte_not_equal) { + rosidl_runtime_cpp::DeprecatedHelperByte f = 8; + rosidl_runtime_cpp::DeprecatedHelperByte g = std::byte{10}; + ASSERT_NE(9, f); + ASSERT_NE(f, 9); + ASSERT_NE(std::byte{11}, static_cast(g)); + ASSERT_NE(static_cast(g), std::byte{11}); + ASSERT_NE(f, g); +} + +TEST(rosidl_generator_cpp, deprecated_helper_byte_to_integer) { + rosidl_runtime_cpp::DeprecatedHelperByte g = std::byte{10}; + ASSERT_EQ(std::to_integer(static_cast(g)), 10); +} + +TEST(rosidl_generator_cpp, deprecated_helper_byte_function_input) { + rosidl_runtime_cpp::DeprecatedHelperByte a = 10; + auto from_deprecated_helper_byte = [](rosidl_runtime_cpp::DeprecatedHelperByte b) {return b;}; + auto from_unsigned_char = [](unsigned char b) {return b;}; + auto from_byte = [](std::byte b) {return b;}; + + ASSERT_EQ(from_deprecated_helper_byte(a), 10); + ASSERT_EQ(from_unsigned_char(a), 10); + ASSERT_EQ(from_byte(static_cast(a)), std::byte{10}); +} + +TEST(rosidl_generator_cpp, deprecated_helper_byte_shifts) { + rosidl_runtime_cpp::DeprecatedHelperByte v = std::byte{1}; + ASSERT_EQ(v << 3, 8); + v <<= 3; + ASSERT_EQ(v, 8); + + rosidl_runtime_cpp::DeprecatedHelperByte g = std::byte{2}; + ASSERT_EQ(static_cast(g) << 3, std::byte{16}); + static_cast(g) <<= 3; + ASSERT_EQ(static_cast(g), std::byte{16}); +} + +#pragma GCC diagnostic pop diff --git a/rosidl_typesupport_introspection_tests/test/introspection_libraries_under_test.hpp b/rosidl_typesupport_introspection_tests/test/introspection_libraries_under_test.hpp index 77b0e3a8c..b85712ebd 100644 --- a/rosidl_typesupport_introspection_tests/test/introspection_libraries_under_test.hpp +++ b/rosidl_typesupport_introspection_tests/test/introspection_libraries_under_test.hpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -933,7 +934,7 @@ struct Example auto message = std::make_unique(); message->bool_values.push_back(true); - message->byte_values.push_back(0x1B); + message->byte_values.push_back(std::byte{0x1B}); message->char_values.push_back('z'); message->float32_values.push_back(12.34f); message->float64_values.push_back(1.234); @@ -1027,7 +1028,7 @@ struct Example auto message = std::make_unique(); message->bool_values.push_back(true); - message->byte_values.push_back(0x1B); + message->byte_values.push_back(std::byte{0x1B}); message->char_values.push_back('z'); message->float32_values.push_back(12.34f); message->float64_values.push_back(1.234); @@ -1079,7 +1080,7 @@ struct Example using MessageT = rosidl_typesupport_introspection_tests::srv::Arrays::Response; auto message = std::make_unique(); - message->byte_values[1] = 0xAB; + message->byte_values[1] = std::byte{0xAB}; message->char_values[0] = 'b'; message->int8_values[2] = 123; return message; @@ -1107,7 +1108,7 @@ struct Example rosidl_typesupport_introspection_tests::srv::BasicTypes::Response; auto message = std::make_unique(); message->bool_value = true; - message->byte_value = 0xAB; + message->byte_value = std::byte{0xAB}; message->float64_value = -1.234; message->string_value = "bar"; return message;