diff --git a/rosidl_adapter/test/test_constant.py b/rosidl_adapter/test/test_constant.py index 26d396abd..f6240c414 100644 --- a/rosidl_adapter/test/test_constant.py +++ b/rosidl_adapter/test/test_constant.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import math + import pytest from rosidl_adapter.parser import Constant @@ -30,6 +32,11 @@ def test_constant_constructor(): with pytest.raises(ValueError): Constant('bool', 'FOO', None) + # NaN is case insensitive in python, so test a few variations. + for nan_string in ['nan', 'Nan', 'NaN', 'NAN', 'nan', 'Nan', 'NaN', 'NAN']: + value = Constant('float32', 'FOO', nan_string) + assert math.isnan(value.value) + def test_constant_methods(): assert Constant('bool', 'FOO', '1') != 23 diff --git a/rosidl_generator_c/resource/idl__struct.h.em b/rosidl_generator_c/resource/idl__struct.h.em index 546507f47..e0f3571c0 100644 --- a/rosidl_generator_c/resource/idl__struct.h.em +++ b/rosidl_generator_c/resource/idl__struct.h.em @@ -32,10 +32,10 @@ extern "C" { #endif +#include #include #include #include - @####################################################################### @# Handle message @####################################################################### diff --git a/rosidl_generator_c/rosidl_generator_c/__init__.py b/rosidl_generator_c/rosidl_generator_c/__init__.py index 4e4bf76d9..673e69565 100644 --- a/rosidl_generator_c/rosidl_generator_c/__init__.py +++ b/rosidl_generator_c/rosidl_generator_c/__init__.py @@ -11,6 +11,7 @@ # 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. +from math import isnan from typing import List @@ -211,10 +212,16 @@ def basic_value_to_c(type_, value): return f'{value}ull' if 'float' == type_.typename: - return f'{value}f' + if isnan(float(value)): + return 'nanf(\"\")' + else: + return f'{value}f' if 'double' == type_.typename: - return f'{value}l' + if isnan(float(value)): + return 'nan(\"\")' + else: + return f'{value}l' assert False, "unknown basic type '%s'" % type_ diff --git a/rosidl_generator_cpp/resource/idl__struct.hpp.em b/rosidl_generator_cpp/resource/idl__struct.hpp.em index c4b7c289e..8f0cfffd3 100644 --- a/rosidl_generator_cpp/resource/idl__struct.hpp.em +++ b/rosidl_generator_cpp/resource/idl__struct.hpp.em @@ -28,6 +28,7 @@ include_directives = set() #include #include +#include #include #include #include diff --git a/rosidl_generator_cpp/resource/msg__struct.hpp.em b/rosidl_generator_cpp/resource/msg__struct.hpp.em index 6e583888f..90cb9e161 100644 --- a/rosidl_generator_cpp/resource/msg__struct.hpp.em +++ b/rosidl_generator_cpp/resource/msg__struct.hpp.em @@ -286,8 +286,12 @@ non_defaulted_zero_initialized_members = [ @[ if constant.type.typename in UNSIGNED_INTEGER_TYPES]@ u@ @[ end if]@ -@[ elif constant.type.typename == 'float']@ - @(constant.value)f@ +@[ elif constant.type.typename == 'float' or constant.type.typename == 'double']@ +@{ +from rosidl_generator_cpp import primitive_value_to_cpp +val = primitive_value_to_cpp(constant.type, constant.value) +}@ + @(val)@ @[ else]@ @(constant.value)@ @[ end if]; diff --git a/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py b/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py index 85db597c7..ed6f70962 100644 --- a/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py +++ b/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py @@ -13,6 +13,7 @@ # limitations under the License. from ast import literal_eval +from math import isnan from typing import List from rosidl_parser.definition import AbstractGenericString @@ -196,6 +197,11 @@ def primitive_value_to_cpp(type_, value): if type_.typename == 'boolean': return 'true' if value else 'false' + if type_.typename in ['double', 'long double', 'float']: + # Handle special floating types here. + if isnan(float(value)): + return f'std::numeric_limits<{type_.typename}>::quiet_NaN()' + if type_.typename in [ 'short', 'unsigned short', 'char', 'wchar', diff --git a/rosidl_generator_tests/CMakeLists.txt b/rosidl_generator_tests/CMakeLists.txt index b2b5d13fd..d81b0dc62 100644 --- a/rosidl_generator_tests/CMakeLists.txt +++ b/rosidl_generator_tests/CMakeLists.txt @@ -35,6 +35,8 @@ if(BUILD_TESTING) ${test_interface_files_MSG_FILES} ${test_interface_files_SRV_FILES} msg/BasicIdl.idl + msg/NanValueConstant.msg + msg/NanValueDefault.msg msg/SmallConstant.msg ADD_LINTER_TESTS SKIP_INSTALL diff --git a/rosidl_generator_tests/msg/NanValueConstant.msg b/rosidl_generator_tests/msg/NanValueConstant.msg new file mode 100644 index 000000000..9dd901085 --- /dev/null +++ b/rosidl_generator_tests/msg/NanValueConstant.msg @@ -0,0 +1,2 @@ +float32 FLOAT32_NAN=NaN +float64 FLOAT64_NAN=nan diff --git a/rosidl_generator_tests/msg/NanValueDefault.msg b/rosidl_generator_tests/msg/NanValueDefault.msg new file mode 100644 index 000000000..98aa6a2a4 --- /dev/null +++ b/rosidl_generator_tests/msg/NanValueDefault.msg @@ -0,0 +1,2 @@ +float32 float32_nan NaN +float64 float64_nan nan 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..0b2ab6e3d 100644 --- a/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp +++ b/rosidl_generator_tests/test/rosidl_generator_cpp/test_interfaces.cpp @@ -41,6 +41,8 @@ #include "rosidl_generator_tests/msg/multi_nested.hpp" #include "rosidl_generator_tests/msg/nested.hpp" #include "rosidl_generator_tests/msg/small_constant.hpp" +#include "rosidl_generator_tests/msg/nan_value_constant.hpp" +#include "rosidl_generator_tests/msg/nan_value_default.hpp" #include "rosidl_generator_tests/msg/strings.hpp" #include "rosidl_generator_tests/msg/unbounded_sequences.hpp" #include "rosidl_generator_tests/msg/w_strings.hpp" @@ -483,6 +485,11 @@ TEST(Test_messages, constants_assign) { ASSERT_EQ(x, rosidl_generator_tests::msg::SmallConstant::FLOAT32_CONST); } +TEST(Test_messages, nan_constants) { + ASSERT_TRUE(std::isnan(rosidl_generator_tests::msg::NanValueConstant::FLOAT32_NAN)); + ASSERT_TRUE(std::isnan(rosidl_generator_tests::msg::NanValueConstant::FLOAT64_NAN)); +} + // Defaults TEST(Test_messages, defaults) { rosidl_generator_tests::msg::Defaults message; @@ -501,6 +508,12 @@ TEST(Test_messages, defaults) { TEST_BASIC_TYPE_FIELD_ASSIGNMENT(message, uint64_value, 50000000ull, UINT64_MAX); } +TEST(Test_messages, nan_defaults) { + rosidl_generator_tests::msg::NanValueDefault nan_val_default; + ASSERT_TRUE(std::isnan(nan_val_default.float32_nan)); + ASSERT_TRUE(std::isnan(nan_val_default.float64_nan)); +} + // String array with default values TEST(Test_messages, string_arrays_default) { rosidl_generator_tests::msg::Arrays message;