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

Add support for NaN constants and NaN defaults in ROS IDL #789

Open
wants to merge 3 commits into
base: rolling
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions rosidl_adapter/test/test_constant.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.

import math

import pytest

from rosidl_adapter.parser import Constant
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_c/resource/idl__struct.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ extern "C"
{
#endif

#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

@#######################################################################
@# Handle message
@#######################################################################
Expand Down
11 changes: 9 additions & 2 deletions rosidl_generator_c/rosidl_generator_c/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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_

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
8 changes: 6 additions & 2 deletions rosidl_generator_cpp/resource/msg__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
6 changes: 6 additions & 0 deletions 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 typing import List

from rosidl_parser.definition import AbstractGenericString
Expand Down Expand Up @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions rosidl_generator_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions rosidl_generator_tests/msg/NanValueConstant.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
float32 FLOAT32_NAN=NaN
float64 FLOAT64_NAN=nan
2 changes: 2 additions & 0 deletions rosidl_generator_tests/msg/NanValueDefault.msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
float32 float32_nan NaN
float64 float64_nan nan
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Loading