Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using NaN default values #825

Closed
wants to merge 5 commits into from
Closed
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
1 change: 1 addition & 0 deletions rosidl_generator_c/resource/idl__struct.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extern "C"
{
#endif

#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
Expand Down
17 changes: 17 additions & 0 deletions rosidl_generator_c/rosidl_generator_c/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from math import isnan

from rosidl_generator_type_description import parse_rihs_string
from rosidl_generator_type_description import RIHS01_HASH_VALUE_SIZE
from rosidl_parser.definition import AbstractGenericString
Expand Down Expand Up @@ -172,6 +174,17 @@ def value_to_c(type_, value):


def basic_value_to_c(type_, value):
"""
Convert a python value into a string representing that value in C.

Warning: The value has to be a primitive and not a list
(aka this function doesn't work for arrays)
@param type_: a ROS IDL basic type
@type type_: builtin.str
@param value: the value to convert
@type value: builtin.str
@returns: a string containing the C representation of the value
"""
assert isinstance(type_, BasicType)
assert value is not None

Expand Down Expand Up @@ -209,9 +222,13 @@ def basic_value_to_c(type_, value):
return f'{value}ull'

if 'float' == type_.typename:
if isnan(float(value)):
return 'NAN'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose to use 'nanf(\"\")' on my PR to avoid the c-style cast to a double later.

return f'{value}f'

if 'double' == type_.typename:
if 'nan' == value:
return '(double)NAN'
return f'{value}l'

assert False, "unknown basic type '%s'" % type_
Expand Down
1 change: 1 addition & 0 deletions rosidl_generator_cpp/resource/idl__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ include_directives = set()
#include <algorithm>
#include <array>
#include <limits>
#include <memory>
#include <string>
#include <vector>
Expand Down
10 changes: 10 additions & 0 deletions rosidl_generator_cpp/resource/msg__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,17 @@ non_defaulted_zero_initialized_members = [
u@
@[ end if]@
@[ elif constant.type.typename == 'float']@
@[ if constant.value == 'nan']
std::numeric_limits<float>::quiet_NaN()@
@[ else]@
@(constant.value)f@
@[ end if]@
@[ elif constant.type.typename == 'double']@
@[ if constant.value == 'nan']
std::numeric_limits<double>::quiet_NaN()@
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of coding this, I chose to use the primitive_value_to_cpp function to promote reuse.

@[ else]@
@(constant.value)f@
@[ end if]@
@[ else]@
@(constant.value)@
@[ end if];
Expand Down
10 changes: 9 additions & 1 deletion rosidl_generator_cpp/rosidl_generator_cpp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

from ast import literal_eval
from math import isnan

from rosidl_parser.definition import AbstractGenericString
from rosidl_parser.definition import AbstractNestedType
Expand Down Expand Up @@ -198,13 +199,18 @@ def primitive_value_to_cpp(type_, value):
if type_.typename in [
'short', 'unsigned short',
'char', 'wchar',
'double', 'long double',
'octet',
'int8', 'uint8',
'int16', 'uint16',
]:
return str(value)

if type_.typename in ['double', 'long double']:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also checked if it was a float here.

if isnan(value):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason, I needed to surroudn value in a float() cast otherwise it threw.

return 'std::numeric_limits<double>::quiet_NaN()'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hard-coding as double, I used the type name here.

else:
return str(value)

if type_.typename == 'int32':
# Handle edge case for INT32_MIN
# Specifically, MSVC is not happy in this case
Expand All @@ -226,6 +232,8 @@ def primitive_value_to_cpp(type_, value):
return '%sull' % value

if type_.typename == 'float':
if isnan(value):
return 'std::numeric_limits<float>::quiet_NaN()'
return '%sf' % value

assert False, "unknown primitive type '%s'" % type_.typename
Expand Down
1 change: 1 addition & 0 deletions rosidl_generator_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ if(BUILD_TESTING)
${test_interface_files_SRV_FILES}
msg/BasicIdl.idl
msg/SmallConstant.msg
msg/NanTest.msg
ADD_LINTER_TESTS
SKIP_INSTALL
)
Expand Down
4 changes: 4 additions & 0 deletions rosidl_generator_tests/msg/NanTest.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
float64 FLOAT64_NAN_UC=NAN
float64 FLOAT64_NAN_LC=nan
float32 FLOAT32_NAN_UC=NAN
float32 FLOAT32_NAN_LC=nan
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#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_test.hpp"
#include "rosidl_generator_tests/msg/strings.hpp"
#include "rosidl_generator_tests/msg/unbounded_sequences.hpp"
#include "rosidl_generator_tests/msg/w_strings.hpp"
Expand Down Expand Up @@ -542,3 +543,16 @@ TEST(Test_messages, Test_string_array_static) {
message.string_values_default.begin());
ASSERT_EQ(pattern_string_values_default, message.string_values_default);
}

TEST(Test_messages, Test_nan) {
float float_nv_uc = rosidl_generator_tests::msg::NanTest::FLOAT32_NAN_UC;
float float_nv_lc = rosidl_generator_tests::msg::NanTest::FLOAT32_NAN_UC;
double double_nv_uc = rosidl_generator_tests::msg::NanTest::FLOAT64_NAN_UC;
double double_nv_lc = rosidl_generator_tests::msg::NanTest::FLOAT64_NAN_UC;

// nan is not equal to nan, so make sure the values are nan
EXPECT_TRUE(std::isnan(float_nv_uc));
EXPECT_TRUE(std::isnan(float_nv_lc));
EXPECT_TRUE(std::isnan(double_nv_uc));
EXPECT_TRUE(std::isnan(double_nv_lc));
}