From 6196d41541a7ecd39345c3bf57ffbf98b472f954 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Mon, 11 Dec 2023 20:06:52 +0800 Subject: [PATCH 01/33] iox-#2055 Rename `fromString` to `from_string` Rename `fromString` to `from_string`. Note that the name of test cases are not included. Signed-off-by: Dennis Liu --- iceoryx_examples/iceperf/main_follower.cpp | 2 +- iceoryx_examples/iceperf/main_leader.cpp | 2 +- .../test/moduletests/test_utility_convert.cpp | 88 +++++++++---------- .../utility/include/iox/detail/convert.hpp | 8 +- .../utility/include/iox/detail/convert.inl | 38 ++++---- .../include/iox/detail/serialization.inl | 6 +- iceoryx_posh/source/roudi/port_manager.cpp | 2 +- iceoryx_posh/source/roudi/roudi.cpp | 6 +- .../source/roudi/roudi_cmd_line_parser.cpp | 6 +- .../source/runtime/ipc_interface_base.cpp | 4 +- .../source/runtime/ipc_runtime_interface.cpp | 10 +-- .../source/runtime/posh_runtime_impl.cpp | 28 +++--- .../source/introspection_app.cpp | 2 +- 13 files changed, 101 insertions(+), 101 deletions(-) diff --git a/iceoryx_examples/iceperf/main_follower.cpp b/iceoryx_examples/iceperf/main_follower.cpp index b810beea53..f9b5a1e0d9 100644 --- a/iceoryx_examples/iceperf/main_follower.cpp +++ b/iceoryx_examples/iceperf/main_follower.cpp @@ -48,7 +48,7 @@ int main(int argc, char* argv[]) constexpr decltype(EXIT_SUCCESS) MOO{EXIT_SUCCESS}; uint64_t intensity{0U}; - if (!iox::convert::fromString(optarg, intensity)) + if (!iox::convert::from_string(optarg, intensity)) { std::cerr << "Could not parse 'intensity' paramater!" << std::endl; return EXIT_FAILURE; diff --git a/iceoryx_examples/iceperf/main_leader.cpp b/iceoryx_examples/iceperf/main_leader.cpp index 30b01bbb82..6e72b00833 100644 --- a/iceoryx_examples/iceperf/main_leader.cpp +++ b/iceoryx_examples/iceperf/main_leader.cpp @@ -116,7 +116,7 @@ int main(int argc, char* argv[]) } break; case 'n': - if (!iox::convert::fromString(optarg, settings.numberOfSamples)) + if (!iox::convert::from_string(optarg, settings.numberOfSamples)) { std::cerr << "Could not parse 'number-of-samples' paramater!" << std::endl; return EXIT_FAILURE; diff --git a/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp b/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp index a3badda763..dd783877c6 100644 --- a/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp +++ b/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp @@ -109,7 +109,7 @@ TEST_F(convert_test, FromString_String) ::testing::Test::RecordProperty("TEST_ID", "22463da5-0fcb-4aa2-a7e5-68b863278a81"); std::string source = "hello"; std::string destination; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(source, Eq(destination)); } @@ -118,7 +118,7 @@ TEST_F(convert_test, fromString_Char_Success) ::testing::Test::RecordProperty("TEST_ID", "a15825c9-536a-4671-a502-6973490022e7"); std::string source = "h"; char destination = '\0'; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(source[0], Eq(destination)); } @@ -127,7 +127,7 @@ TEST_F(convert_test, fromString_Char_Fail) ::testing::Test::RecordProperty("TEST_ID", "656e87ad-6fdb-42d7-bf49-23f81a4f5a31"); std::string source = "hasd"; char destination = '\0'; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, stringIsNumber_IsINTEGER) @@ -189,7 +189,7 @@ TEST_F(convert_test, fromString_FLOAT_Success) ::testing::Test::RecordProperty("TEST_ID", "d6255c3e-369e-43a0-a1ab-03f7b13d03c2"); std::string source = "123.01"; float destination = 0.0F; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_FLOAT_EQ(destination, 123.01F); } @@ -198,7 +198,7 @@ TEST_F(convert_test, fromString_FLOAT_Fail) ::testing::Test::RecordProperty("TEST_ID", "e2b94d50-664c-4f9e-be4f-99212c6fa165"); std::string source = "hasd"; float destination = 0.0F; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_Double_Success) @@ -206,7 +206,7 @@ TEST_F(convert_test, fromString_Double_Success) ::testing::Test::RecordProperty("TEST_ID", "95ba379e-120e-4b80-a829-33fe54f1bfed"); std::string source = "123.04"; double destination = 0.0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(destination, Eq(123.04)); } @@ -215,7 +215,7 @@ TEST_F(convert_test, fromString_Double_Fail) ::testing::Test::RecordProperty("TEST_ID", "f4ace11b-a056-47b1-b6c5-6fb2c58e1a06"); std::string source = "hasd"; double destination = 0.0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_LongDouble_Success) @@ -224,7 +224,7 @@ TEST_F(convert_test, fromString_LongDouble_Success) std::string source = "121.01"; long double destination = 0.0; constexpr long double VERIFY = 121.01; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(static_cast(destination), DoubleEq(static_cast(VERIFY))); } @@ -233,7 +233,7 @@ TEST_F(convert_test, fromString_LongDouble_Fail) ::testing::Test::RecordProperty("TEST_ID", "519f2ac5-8836-419e-8034-377230a88a09"); std::string source = "hasd"; double destination = 0.0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_UNSIGNED_Int_Success) @@ -241,7 +241,7 @@ TEST_F(convert_test, fromString_UNSIGNED_Int_Success) ::testing::Test::RecordProperty("TEST_ID", "1edb8d5f-c42d-4d02-bc31-477f48898bbb"); std::string source = "100"; unsigned int destination = 0.0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(destination, Eq(100U)); } @@ -250,7 +250,7 @@ TEST_F(convert_test, fromString_UNSIGNED_Int_Fail) ::testing::Test::RecordProperty("TEST_ID", "6ce6de82-a6c0-4562-9c5c-663b93d768b3"); std::string source = "-331"; unsigned int destination = 0U; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_UNSIGNED_LongInt_Success) @@ -258,7 +258,7 @@ TEST_F(convert_test, fromString_UNSIGNED_LongInt_Success) ::testing::Test::RecordProperty("TEST_ID", "054b08b2-54e1-4191-91b6-e6bec415612f"); std::string source = "999"; uint64_t destination = 0U; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(destination, Eq(999LU)); } @@ -267,7 +267,7 @@ TEST_F(convert_test, fromString_UNSIGNED_LongInt_Fail) ::testing::Test::RecordProperty("TEST_ID", "4b215747-90b2-4ca2-97ee-517c07597b1b"); std::string source = "-a123"; uint64_t destination = 0U; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_Int_Success) @@ -275,7 +275,7 @@ TEST_F(convert_test, fromString_Int_Success) ::testing::Test::RecordProperty("TEST_ID", "9318ee60-f2e0-445a-b32d-c718cf918b18"); std::string source = "3331"; int destination = 0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(destination, Eq(3331)); } @@ -284,7 +284,7 @@ TEST_F(convert_test, fromString_Int_Fail) ::testing::Test::RecordProperty("TEST_ID", "f8e698a9-054d-4441-b196-bcd58a72b1d9"); std::string source = "-+321"; int destination = 0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_ShortInt_Success) @@ -292,7 +292,7 @@ TEST_F(convert_test, fromString_ShortInt_Success) ::testing::Test::RecordProperty("TEST_ID", "e804f821-157d-4c52-81a7-75fce5a43805"); std::string source = "12345"; short destination = 0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(destination, Eq(12345)); } @@ -301,7 +301,7 @@ TEST_F(convert_test, fromString_ShortInt_Fail) ::testing::Test::RecordProperty("TEST_ID", "1150066b-cb42-4055-9927-2f20fb40bc87"); std::string source = "-+123321"; short destination = 0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_Bool_Success) @@ -309,7 +309,7 @@ TEST_F(convert_test, fromString_Bool_Success) ::testing::Test::RecordProperty("TEST_ID", "893723fc-dfb8-46a4-b446-badaf8bad25a"); std::string source = "1"; bool destination = false; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(destination, Eq(true)); } @@ -318,7 +318,7 @@ TEST_F(convert_test, fromString_Bool_Fail) ::testing::Test::RecordProperty("TEST_ID", "1c937da6-29ea-49cf-a7d0-4c46f564c16e"); std::string source = "-+222"; bool destination = false; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_UShortInt_Success) @@ -326,7 +326,7 @@ TEST_F(convert_test, fromString_UShortInt_Success) ::testing::Test::RecordProperty("TEST_ID", "99d22d80-3860-47fa-9f98-f11ff9629815"); std::string source = "333"; unsigned short destination = 0U; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(destination, Eq(333)); } @@ -335,7 +335,7 @@ TEST_F(convert_test, fromString_UShortInt_Fail) ::testing::Test::RecordProperty("TEST_ID", "6ab6ded6-dff3-401a-8a7f-98326da7cca6"); std::string source = "-+111"; unsigned short destination = 0U; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_LongInt_Success) @@ -343,7 +343,7 @@ TEST_F(convert_test, fromString_LongInt_Success) ::testing::Test::RecordProperty("TEST_ID", "37133256-ae79-45c7-8c86-56bd33fa7bd8"); std::string source = "-1123"; int64_t destination = 0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); EXPECT_THAT(destination, Eq(-1123L)); } @@ -352,7 +352,7 @@ TEST_F(convert_test, fromString_LongInt_Fail) ::testing::Test::RecordProperty("TEST_ID", "0e368bf3-cb16-4829-a4cc-dc56e0bde958"); std::string source = "-a121"; int64_t destination = 0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_MinMaxShort) @@ -360,13 +360,13 @@ TEST_F(convert_test, fromString_MinMaxShort) ::testing::Test::RecordProperty("TEST_ID", "98e33efd-ba39-4b88-8307-358be30e4e73"); std::string source = "32767"; int16_t destination = 0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "32768"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); source = "-32768"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "-32769"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_MinMaxUNSIGNED_Short) @@ -374,13 +374,13 @@ TEST_F(convert_test, fromString_MinMaxUNSIGNED_Short) ::testing::Test::RecordProperty("TEST_ID", "f9196939-ae5d-4c27-85bf-b3b084343261"); std::string source = "65535"; uint16_t destination = 0U; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "65536"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); source = "0"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "-1"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_MinMaxInt) @@ -388,13 +388,13 @@ TEST_F(convert_test, fromString_MinMaxInt) ::testing::Test::RecordProperty("TEST_ID", "abf0fda5-044e-4f1b-bb1e-31b701578a3d"); std::string source = "2147483647"; int32_t destination = 0; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "2147483648"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); source = "-2147483648"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "-2147483649"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_MinMaxUNSIGNED_Int) @@ -402,13 +402,13 @@ TEST_F(convert_test, fromString_MinMaxUNSIGNED_Int) ::testing::Test::RecordProperty("TEST_ID", "c2a832ef-3e86-4303-a98c-63c7b11ea789"); std::string source = "4294967295"; uint32_t destination = 0U; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "4294967296"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); source = "0"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "-1"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } TEST_F(convert_test, fromString_cxxString) @@ -416,15 +416,15 @@ TEST_F(convert_test, fromString_cxxString) ::testing::Test::RecordProperty("TEST_ID", "dbf015bb-5f51-47e1-9d0e-0525f65e7803"); std::string source = "hello"; iox::string<8> destination; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = ""; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "12345678"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); source = "123456789"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); source = "this_is_a_very_long_string"; - EXPECT_THAT(iox::convert::fromString(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); } } // namespace diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index faf2053b81..66e3204ae5 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -40,8 +40,8 @@ namespace iox /// /// int i; /// unsigned int a; -/// if ( iox::convert::fromString("123", i) ) {} // will succeed -/// if ( iox::convert::fromString("-123", a) ) {} // will fail since -123 is not unsigned +/// if ( iox::convert::from_string("123", i) ) {} // will succeed +/// if ( iox::convert::from_string("-123", a) ) {} // will fail since -123 is not unsigned /// @endcode /// @todo iox-#260 Refactor 'convert' so that one can use 'into' to directly to convert numbers to strings: /// 'ClassExpectingAnIoxString(iox::into>(42)' @@ -81,7 +81,7 @@ class convert /// @param[in] dest destination to which the value should be written /// @return false = if the conversion fails otherwise true template - static bool fromString(const char* v, Destination& dest) noexcept; + static bool from_string(const char* v, Destination& dest) noexcept; /// @brief Sets dest from a given string. If the conversion fails false is /// returned and the value of dest is undefined. @@ -89,7 +89,7 @@ class convert /// @param[in] dest destination to which the value should be written /// @return false = if the conversion fails otherwise true template - static bool fromString(const char* v, string& dest) noexcept; + static bool from_string(const char* v, string& dest) noexcept; /// @brief checks if a given string v is a number /// @param[in] v string which contains the number diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index f2463f5cca..86ee73aa5e 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -58,14 +58,14 @@ convert::toString(const Source& t) noexcept } template -inline bool convert::fromString(const char* v, Destination& dest) noexcept +inline bool convert::from_string(const char* v, Destination& dest) noexcept { dest = Destination(v); return true; } template <> -inline bool convert::fromString(const char* v, char& dest) noexcept +inline bool convert::from_string(const char* v, char& dest) noexcept { if (strlen(v) != 1U) { @@ -80,7 +80,7 @@ inline bool convert::fromString(const char* v, char& dest) noexcept } template -inline bool convert::fromString(const char* v, string& dest) noexcept +inline bool convert::from_string(const char* v, string& dest) noexcept { if (strlen(v) > Capacity) { @@ -157,7 +157,7 @@ inline bool convert::stringIsNumberWithErrorMessage(const char* v, const NumberT } template <> -inline bool convert::fromString(const char* v, float& dest) noexcept +inline bool convert::from_string(const char* v, float& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT)) { @@ -172,7 +172,7 @@ inline bool convert::fromString(const char* v, float& dest) noexcept } template <> -inline bool convert::fromString(const char* v, double& dest) noexcept +inline bool convert::from_string(const char* v, double& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT)) { @@ -187,7 +187,7 @@ inline bool convert::fromString(const char* v, double& dest) noexcept } template <> -inline bool convert::fromString(const char* v, long double& dest) noexcept +inline bool convert::from_string(const char* v, long double& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT)) { @@ -202,7 +202,7 @@ inline bool convert::fromString(const char* v, long double& dest) n } template <> -inline bool convert::fromString(const char* v, uint64_t& dest) noexcept +inline bool convert::from_string(const char* v, uint64_t& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) { @@ -230,10 +230,10 @@ inline bool convert::fromString(const char* v, uint64_t& dest) noexcep /// introduced for mac os since unsigned long is not uint64_t despite it has the same size /// who knows why ¯\_(ツ)_/¯ template <> -inline bool convert::fromString(const char* v, unsigned long& dest) noexcept +inline bool convert::from_string(const char* v, unsigned long& dest) noexcept { uint64_t temp{0}; - bool retVal = fromString(v, temp); + bool retVal = from_string(v, temp); dest = temp; return retVal; } @@ -243,17 +243,17 @@ inline bool convert::fromString(const char* v, unsigned long& des /// introduced for 32-bit arm-none-eabi-gcc since uintptr_t is not uint32_t despite it has the same size /// who knows why ¯\_(ツ)_/¯ template <> -inline bool convert::fromString(const char* v, uintptr_t& dest) noexcept +inline bool convert::from_string(const char* v, uintptr_t& dest) noexcept { uint64_t temp{0}; - bool retVal = fromString(v, temp); + bool retVal = from_string(v, temp); dest = temp; return retVal; } #endif template <> -inline bool convert::fromString(const char* v, uint32_t& dest) noexcept +inline bool convert::from_string(const char* v, uint32_t& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) { @@ -278,7 +278,7 @@ inline bool convert::fromString(const char* v, uint32_t& dest) noexcep } template <> -inline bool convert::fromString(const char* v, uint16_t& dest) noexcept +inline bool convert::from_string(const char* v, uint16_t& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) { @@ -303,7 +303,7 @@ inline bool convert::fromString(const char* v, uint16_t& dest) noexcep } template <> -inline bool convert::fromString(const char* v, uint8_t& dest) noexcept +inline bool convert::from_string(const char* v, uint8_t& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) { @@ -328,7 +328,7 @@ inline bool convert::fromString(const char* v, uint8_t& dest) noexcept } template <> -inline bool convert::fromString(const char* v, int64_t& dest) noexcept +inline bool convert::from_string(const char* v, int64_t& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER)) { @@ -352,7 +352,7 @@ inline bool convert::fromString(const char* v, int64_t& dest) noexcept } template <> -inline bool convert::fromString(const char* v, int32_t& dest) noexcept +inline bool convert::from_string(const char* v, int32_t& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER)) { @@ -376,7 +376,7 @@ inline bool convert::fromString(const char* v, int32_t& dest) noexcept } template <> -inline bool convert::fromString(const char* v, int16_t& dest) noexcept +inline bool convert::from_string(const char* v, int16_t& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER)) { @@ -400,7 +400,7 @@ inline bool convert::fromString(const char* v, int16_t& dest) noexcept } template <> -inline bool convert::fromString(const char* v, int8_t& dest) noexcept +inline bool convert::from_string(const char* v, int8_t& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER)) { @@ -424,7 +424,7 @@ inline bool convert::fromString(const char* v, int8_t& dest) noexcept } template <> -inline bool convert::fromString(const char* v, bool& dest) noexcept +inline bool convert::from_string(const char* v, bool& dest) noexcept { if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) { diff --git a/iceoryx_hoofs/utility/include/iox/detail/serialization.inl b/iceoryx_hoofs/utility/include/iox/detail/serialization.inl index bbee4acfc5..9e6789eb6a 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/serialization.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/serialization.inl @@ -94,7 +94,7 @@ inline bool Serialization::deserialize(const std::string& serializedString, T& t return false; } - if (!convert::fromString(entry.c_str(), t)) + if (!convert::from_string(entry.c_str(), t)) { return false; } @@ -111,7 +111,7 @@ inline bool Serialization::removeFirstEntry(std::string& firstEntry, std::string } uint64_t length{0}; - if (!convert::fromString(remainder.substr(0, pos).c_str(), length)) + if (!convert::from_string(remainder.substr(0, pos).c_str(), length)) { return false; } @@ -140,7 +140,7 @@ inline bool Serialization::getNth(const unsigned int index, T& t) const noexcept } } - return convert::fromString(entry.c_str(), t); + return convert::from_string(entry.c_str(), t); } } // namespace iox diff --git a/iceoryx_posh/source/roudi/port_manager.cpp b/iceoryx_posh/source/roudi/port_manager.cpp index 315c66d231..87d64a83ab 100644 --- a/iceoryx_posh/source/roudi/port_manager.cpp +++ b/iceoryx_posh/source/roudi/port_manager.cpp @@ -32,7 +32,7 @@ namespace roudi capro::Interfaces StringToCaProInterface(const capro::IdString_t& str) noexcept { int32_t i{0}; - convert::fromString(str.c_str(), i); + convert::from_string(str.c_str(), i); if (i >= static_cast(capro::Interfaces::INTERFACE_END)) { IOX_LOG(WARN, "invalid enum (out of range: " << i << ")"); diff --git a/iceoryx_posh/source/roudi/roudi.cpp b/iceoryx_posh/source/roudi/roudi.cpp index 5d88904dd9..c88244a5cc 100644 --- a/iceoryx_posh/source/roudi/roudi.cpp +++ b/iceoryx_posh/source/roudi/roudi.cpp @@ -270,9 +270,9 @@ version::VersionInfo RouDi::parseRegisterMessage(const runtime::IpcMessage& mess uid_t& userId, int64_t& transmissionTimestamp) noexcept { - convert::fromString(message.getElementAtIndex(2).c_str(), pid); - convert::fromString(message.getElementAtIndex(3).c_str(), userId); - convert::fromString(message.getElementAtIndex(4).c_str(), transmissionTimestamp); + convert::from_string(message.getElementAtIndex(2).c_str(), pid); + convert::from_string(message.getElementAtIndex(3).c_str(), userId); + convert::from_string(message.getElementAtIndex(4).c_str(), transmissionTimestamp); Serialization serializationVersionInfo(message.getElementAtIndex(5)); return serializationVersionInfo; } diff --git a/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp b/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp index 355bbb8e2f..5645e839f8 100644 --- a/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp +++ b/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp @@ -100,7 +100,7 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm { uint16_t roudiId{0u}; constexpr uint64_t MAX_ROUDI_ID = ((1 << 16) - 1); - if (!convert::fromString(optarg, roudiId)) + if (!convert::from_string(optarg, roudiId)) { IOX_LOG(ERROR, "The RouDi id must be in the range of [0, " << MAX_ROUDI_ID << "]"); m_cmdLineArgs.run = false; @@ -168,7 +168,7 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm { uint32_t processTerminationDelayInSeconds{0u}; constexpr uint64_t MAX_PROCESS_TERMINATION_DELAY = std::numeric_limits::max(); - if (!convert::fromString(optarg, processTerminationDelayInSeconds)) + if (!convert::from_string(optarg, processTerminationDelayInSeconds)) { IOX_LOG(ERROR, "The process termination delay must be in the range of [0, " << MAX_PROCESS_TERMINATION_DELAY @@ -185,7 +185,7 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm { uint32_t processKillDelayInSeconds{0u}; constexpr uint64_t MAX_PROCESS_KILL_DELAY = std::numeric_limits::max(); - if (!convert::fromString(optarg, processKillDelayInSeconds)) + if (!convert::from_string(optarg, processKillDelayInSeconds)) { IOX_LOG(ERROR, "The process kill delay must be in the range of [0, " << MAX_PROCESS_KILL_DELAY << "]"); m_cmdLineArgs.run = false; diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index c553d32258..8cf98ea33a 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -30,7 +30,7 @@ IpcMessageType stringToIpcMessageType(const char* str) noexcept { std::underlying_type::type msg; bool noError = convert::stringIsNumber(str, convert::NumberType::INTEGER); - noError &= noError ? (convert::fromString(str, msg)) : false; + noError &= noError ? (convert::from_string(str, msg)) : false; noError &= noError ? !(static_cast::type>(IpcMessageType::BEGIN) >= msg || static_cast::type>(IpcMessageType::END) <= msg) : false; @@ -46,7 +46,7 @@ IpcMessageErrorType stringToIpcMessageErrorType(const char* str) noexcept { std::underlying_type::type msg; bool noError = convert::stringIsNumber(str, convert::NumberType::INTEGER); - noError &= noError ? (convert::fromString(str, msg)) : false; + noError &= noError ? (convert::from_string(str, msg)) : false; noError &= noError ? !(static_cast::type>(IpcMessageErrorType::BEGIN) >= msg || static_cast::type>(IpcMessageErrorType::END) <= msg) diff --git a/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp b/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp index e3e5477387..028dafd62b 100644 --- a/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp +++ b/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp @@ -235,16 +235,16 @@ IpcRuntimeInterface::RegAckResult IpcRuntimeInterface::waitForRegAck(int64_t tra } // read out the shared memory base address and save it - iox::convert::fromString(receiveBuffer.getElementAtIndex(1U).c_str(), m_shmTopicSize); + iox::convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), m_shmTopicSize); UntypedRelativePointer::offset_t segmentManagerOffset{UntypedRelativePointer::NULL_POINTER_OFFSET}; - iox::convert::fromString(receiveBuffer.getElementAtIndex(2U).c_str(), segmentManagerOffset); + iox::convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentManagerOffset); m_segmentManagerAddressOffset.emplace(segmentManagerOffset); int64_t receivedTimestamp{0U}; - iox::convert::fromString(receiveBuffer.getElementAtIndex(3U).c_str(), receivedTimestamp); - iox::convert::fromString(receiveBuffer.getElementAtIndex(4U).c_str(), m_segmentId); + iox::convert::from_string(receiveBuffer.getElementAtIndex(3U).c_str(), receivedTimestamp); + iox::convert::from_string(receiveBuffer.getElementAtIndex(4U).c_str(), m_segmentId); UntypedRelativePointer::offset_t heartbeatOffset{UntypedRelativePointer::NULL_POINTER_OFFSET}; - iox::convert::fromString(receiveBuffer.getElementAtIndex(5U).c_str(), heartbeatOffset); + iox::convert::from_string(receiveBuffer.getElementAtIndex(5U).c_str(), heartbeatOffset); /// @todo iox-#2055 this workaround is required sind the conversion of edge cases is broken constexpr uint8_t IOX_2055_WORKAROUND{1}; if (heartbeatOffset != (UntypedRelativePointer::NULL_POINTER_OFFSET - IOX_2055_WORKAROUND)) diff --git a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp index b029657c79..e8a4e7dc51 100644 --- a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp +++ b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp @@ -188,9 +188,9 @@ PoshRuntimeImpl::requestPublisherFromRoudi(const IpcMessage& sendBuffer) noexcep { segment_id_underlying_t segmentId{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } @@ -300,9 +300,9 @@ PoshRuntimeImpl::requestSubscriberFromRoudi(const IpcMessage& sendBuffer) noexce if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_SUBSCRIBER_ACK) { segment_id_underlying_t segmentId{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } @@ -408,9 +408,9 @@ PoshRuntimeImpl::requestClientFromRoudi(const IpcMessage& sendBuffer) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_CLIENT_ACK) { segment_id_underlying_t segmentId{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } @@ -516,9 +516,9 @@ PoshRuntimeImpl::requestServerFromRoudi(const IpcMessage& sendBuffer) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_SERVER_ACK) { segment_id_underlying_t segmentId{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } @@ -560,9 +560,9 @@ popo::InterfacePortData* PoshRuntimeImpl::getMiddlewareInterface(const capro::In if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_INTERFACE_ACK) { segment_id_underlying_t segmentId{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return reinterpret_cast(ptr); } @@ -594,9 +594,9 @@ NodeData* PoshRuntimeImpl::createNode(const NodeProperty& nodeProperty) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_NODE_ACK) { segment_id_underlying_t segmentId{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return reinterpret_cast(ptr); } @@ -623,9 +623,9 @@ PoshRuntimeImpl::requestConditionVariableFromRoudi(const IpcMessage& sendBuffer) if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_CONDITION_VARIABLE_ACK) { segment_id_underlying_t segmentId{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::fromString(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } diff --git a/tools/introspection/source/introspection_app.cpp b/tools/introspection/source/introspection_app.cpp index a3ea91f5f5..4ceb70ca55 100644 --- a/tools/introspection/source/introspection_app.cpp +++ b/tools/introspection/source/introspection_app.cpp @@ -102,7 +102,7 @@ void IntrospectionApp::parseCmdLineArguments(int argc, case 't': { uint64_t newUpdatePeriodMs; - if (convert::fromString(optarg, newUpdatePeriodMs)) + if (convert::from_string(optarg, newUpdatePeriodMs)) { iox::units::Duration rate = iox::units::Duration::fromMilliseconds(newUpdatePeriodMs); updatePeriodMs = bounded(rate, MIN_UPDATE_PERIOD, MAX_UPDATE_PERIOD); From 40165556924925c5ff9c3f8ed3c2518b45e44479 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Mon, 11 Dec 2023 20:46:27 +0800 Subject: [PATCH 02/33] iox-#2055 Remove `convert::stringIsNumber` related func Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 9 -- .../utility/include/iox/detail/convert.inl | 125 ------------------ .../source/runtime/ipc_interface_base.cpp | 6 +- 3 files changed, 2 insertions(+), 138 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index 66e3204ae5..dd9cea88d1 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -90,15 +90,6 @@ class convert /// @return false = if the conversion fails otherwise true template static bool from_string(const char* v, string& dest) noexcept; - - /// @brief checks if a given string v is a number - /// @param[in] v string which contains the number - /// @param[in] type is the expected contained type in v - /// @return true if the given string is a number, otherwise false - static bool stringIsNumber(const char* v, const NumberType type) noexcept; - - private: - static bool stringIsNumberWithErrorMessage(const char* v, const NumberType type) noexcept; }; } // namespace iox diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 86ee73aa5e..d5f01c72f5 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -91,79 +91,9 @@ inline bool convert::from_string(const char* v, string& dest) noexcept return true; } -inline bool convert::stringIsNumber(const char* v, const NumberType type) noexcept -{ - /// @NOLINTJUSTIFICATION encapsulated in abstraction - /// @NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - if (v[0] == '\0') - { - return false; - } - - bool hasDot = false; - - for (uint32_t i = 0U; v[i] != '\0'; ++i) - { - if (v[i] >= '0' && v[i] <= '9') - { - continue; - } - - if (type != NumberType::UNSIGNED_INTEGER && i == 0U && (v[i] == '+' || v[i] == '-')) - { - continue; - } - - if (type == NumberType::FLOAT && !hasDot && v[i] == '.') - { - hasDot = true; - } - else - { - return false; - } - } - /// @NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - return true; -} - -inline bool convert::stringIsNumberWithErrorMessage(const char* v, const NumberType type) noexcept -{ - if (!stringIsNumber(v, type)) - { - IOX_LOG(DEBUG, v << " is not "); - switch (type) - { - case NumberType::FLOAT: - { - IOX_LOG(DEBUG, "a float"); - break; - } - case NumberType::INTEGER: - { - IOX_LOG(DEBUG, "a signed integer"); - break; - } - case NumberType::UNSIGNED_INTEGER: - { - IOX_LOG(DEBUG, "an unsigned integer"); - break; - } - } - return false; - } - return true; -} - template <> inline bool convert::from_string(const char* v, float& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT)) - { - return false; - } - return !IOX_POSIX_CALL(strtof)(v, nullptr) .failureReturnValue(HUGE_VALF, -HUGE_VALF) .evaluate() @@ -174,11 +104,6 @@ inline bool convert::from_string(const char* v, float& dest) noexcept template <> inline bool convert::from_string(const char* v, double& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT)) - { - return false; - } - return !IOX_POSIX_CALL(strtod)(v, nullptr) .failureReturnValue(HUGE_VAL, -HUGE_VAL) .evaluate() @@ -189,11 +114,6 @@ inline bool convert::from_string(const char* v, double& dest) noexcept template <> inline bool convert::from_string(const char* v, long double& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::FLOAT)) - { - return false; - } - return !IOX_POSIX_CALL(strtold)(v, nullptr) .failureReturnValue(HUGE_VALL, -HUGE_VALL) .evaluate() @@ -204,11 +124,6 @@ inline bool convert::from_string(const char* v, long double& dest) template <> inline bool convert::from_string(const char* v, uint64_t& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) - { - return false; - } - auto call = IOX_POSIX_CALL(strtoull)(v, nullptr, STRTOULL_BASE).failureReturnValue(ULLONG_MAX).evaluate(); if (call.has_error()) @@ -255,11 +170,6 @@ inline bool convert::from_string(const char* v, uintptr_t& dest) noex template <> inline bool convert::from_string(const char* v, uint32_t& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) - { - return false; - } - auto call = IOX_POSIX_CALL(strtoull)(v, nullptr, STRTOULL_BASE).failureReturnValue(ULLONG_MAX).evaluate(); if (call.has_error()) @@ -280,11 +190,6 @@ inline bool convert::from_string(const char* v, uint32_t& dest) noexce template <> inline bool convert::from_string(const char* v, uint16_t& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) - { - return false; - } - auto call = IOX_POSIX_CALL(strtoul)(v, nullptr, STRTOULL_BASE).failureReturnValue(ULONG_MAX).evaluate(); if (call.has_error()) @@ -305,11 +210,6 @@ inline bool convert::from_string(const char* v, uint16_t& dest) noexce template <> inline bool convert::from_string(const char* v, uint8_t& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) - { - return false; - } - auto call = IOX_POSIX_CALL(strtoul)(v, nullptr, STRTOULL_BASE).failureReturnValue(ULONG_MAX).evaluate(); if (call.has_error()) @@ -330,11 +230,6 @@ inline bool convert::from_string(const char* v, uint8_t& dest) noexcept template <> inline bool convert::from_string(const char* v, int64_t& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER)) - { - return false; - } - auto call = IOX_POSIX_CALL(strtoll)(v, nullptr, STRTOULL_BASE).failureReturnValue(LLONG_MAX, LLONG_MIN).evaluate(); if (call.has_error()) { @@ -354,11 +249,6 @@ inline bool convert::from_string(const char* v, int64_t& dest) noexcept template <> inline bool convert::from_string(const char* v, int32_t& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER)) - { - return false; - } - auto call = IOX_POSIX_CALL(strtoll)(v, nullptr, STRTOULL_BASE).failureReturnValue(LLONG_MAX, LLONG_MIN).evaluate(); if (call.has_error()) { @@ -378,11 +268,6 @@ inline bool convert::from_string(const char* v, int32_t& dest) noexcept template <> inline bool convert::from_string(const char* v, int16_t& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER)) - { - return false; - } - auto call = IOX_POSIX_CALL(strtol)(v, nullptr, STRTOULL_BASE).failureReturnValue(LONG_MAX, LONG_MIN).evaluate(); if (call.has_error()) { @@ -402,11 +287,6 @@ inline bool convert::from_string(const char* v, int16_t& dest) noexcept template <> inline bool convert::from_string(const char* v, int8_t& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::INTEGER)) - { - return false; - } - auto call = IOX_POSIX_CALL(strtol)(v, nullptr, STRTOULL_BASE).failureReturnValue(LONG_MAX, LONG_MIN).evaluate(); if (call.has_error()) { @@ -426,11 +306,6 @@ inline bool convert::from_string(const char* v, int8_t& dest) noexcept template <> inline bool convert::from_string(const char* v, bool& dest) noexcept { - if (!stringIsNumberWithErrorMessage(v, NumberType::UNSIGNED_INTEGER)) - { - return false; - } - return !IOX_POSIX_CALL(strtoul)(v, nullptr, STRTOULL_BASE) .failureReturnValue(ULONG_MAX) .evaluate() diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index 8cf98ea33a..c68e3ccc4f 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -29,8 +29,7 @@ namespace runtime IpcMessageType stringToIpcMessageType(const char* str) noexcept { std::underlying_type::type msg; - bool noError = convert::stringIsNumber(str, convert::NumberType::INTEGER); - noError &= noError ? (convert::from_string(str, msg)) : false; + bool noError = convert::from_string(str, msg); noError &= noError ? !(static_cast::type>(IpcMessageType::BEGIN) >= msg || static_cast::type>(IpcMessageType::END) <= msg) : false; @@ -45,8 +44,7 @@ std::string IpcMessageTypeToString(const IpcMessageType msg) noexcept IpcMessageErrorType stringToIpcMessageErrorType(const char* str) noexcept { std::underlying_type::type msg; - bool noError = convert::stringIsNumber(str, convert::NumberType::INTEGER); - noError &= noError ? (convert::from_string(str, msg)) : false; + bool noError = (convert::from_string(str, msg)); noError &= noError ? !(static_cast::type>(IpcMessageErrorType::BEGIN) >= msg || static_cast::type>(IpcMessageErrorType::END) <= msg) From 60b7c798b30ed9069ab502e9bb94eb5bdc212b9e Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Mon, 11 Dec 2023 22:52:13 +0800 Subject: [PATCH 03/33] iox-#2055 Add local variable `end_ptr` Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.inl | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index d5f01c72f5..d290408ed4 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -94,7 +94,9 @@ inline bool convert::from_string(const char* v, string& dest) noexcept template <> inline bool convert::from_string(const char* v, float& dest) noexcept { - return !IOX_POSIX_CALL(strtof)(v, nullptr) + char* end_ptr = nullptr; + + return !IOX_POSIX_CALL(strtof)(v, &end_ptr) .failureReturnValue(HUGE_VALF, -HUGE_VALF) .evaluate() .and_then([&](auto& r) { dest = r.value; }) @@ -104,7 +106,9 @@ inline bool convert::from_string(const char* v, float& dest) noexcept template <> inline bool convert::from_string(const char* v, double& dest) noexcept { - return !IOX_POSIX_CALL(strtod)(v, nullptr) + char* end_ptr = nullptr; + + return !IOX_POSIX_CALL(strtod)(v, &end_ptr) .failureReturnValue(HUGE_VAL, -HUGE_VAL) .evaluate() .and_then([&](auto& r) { dest = r.value; }) @@ -114,7 +118,9 @@ inline bool convert::from_string(const char* v, double& dest) noexcept template <> inline bool convert::from_string(const char* v, long double& dest) noexcept { - return !IOX_POSIX_CALL(strtold)(v, nullptr) + char* end_ptr = nullptr; + + return !IOX_POSIX_CALL(strtold)(v, &end_ptr) .failureReturnValue(HUGE_VALL, -HUGE_VALL) .evaluate() .and_then([&](auto& r) { dest = r.value; }) @@ -124,7 +130,9 @@ inline bool convert::from_string(const char* v, long double& dest) template <> inline bool convert::from_string(const char* v, uint64_t& dest) noexcept { - auto call = IOX_POSIX_CALL(strtoull)(v, nullptr, STRTOULL_BASE).failureReturnValue(ULLONG_MAX).evaluate(); + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(ULLONG_MAX).evaluate(); if (call.has_error()) { @@ -170,7 +178,9 @@ inline bool convert::from_string(const char* v, uintptr_t& dest) noex template <> inline bool convert::from_string(const char* v, uint32_t& dest) noexcept { - auto call = IOX_POSIX_CALL(strtoull)(v, nullptr, STRTOULL_BASE).failureReturnValue(ULLONG_MAX).evaluate(); + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(ULLONG_MAX).evaluate(); if (call.has_error()) { @@ -190,7 +200,9 @@ inline bool convert::from_string(const char* v, uint32_t& dest) noexce template <> inline bool convert::from_string(const char* v, uint16_t& dest) noexcept { - auto call = IOX_POSIX_CALL(strtoul)(v, nullptr, STRTOULL_BASE).failureReturnValue(ULONG_MAX).evaluate(); + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(ULONG_MAX).evaluate(); if (call.has_error()) { @@ -210,7 +222,9 @@ inline bool convert::from_string(const char* v, uint16_t& dest) noexce template <> inline bool convert::from_string(const char* v, uint8_t& dest) noexcept { - auto call = IOX_POSIX_CALL(strtoul)(v, nullptr, STRTOULL_BASE).failureReturnValue(ULONG_MAX).evaluate(); + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(ULONG_MAX).evaluate(); if (call.has_error()) { @@ -230,7 +244,9 @@ inline bool convert::from_string(const char* v, uint8_t& dest) noexcept template <> inline bool convert::from_string(const char* v, int64_t& dest) noexcept { - auto call = IOX_POSIX_CALL(strtoll)(v, nullptr, STRTOULL_BASE).failureReturnValue(LLONG_MAX, LLONG_MIN).evaluate(); + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(LLONG_MAX, LLONG_MIN).evaluate(); if (call.has_error()) { return false; @@ -249,7 +265,9 @@ inline bool convert::from_string(const char* v, int64_t& dest) noexcept template <> inline bool convert::from_string(const char* v, int32_t& dest) noexcept { - auto call = IOX_POSIX_CALL(strtoll)(v, nullptr, STRTOULL_BASE).failureReturnValue(LLONG_MAX, LLONG_MIN).evaluate(); + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(LLONG_MAX, LLONG_MIN).evaluate(); if (call.has_error()) { return false; @@ -268,7 +286,9 @@ inline bool convert::from_string(const char* v, int32_t& dest) noexcept template <> inline bool convert::from_string(const char* v, int16_t& dest) noexcept { - auto call = IOX_POSIX_CALL(strtol)(v, nullptr, STRTOULL_BASE).failureReturnValue(LONG_MAX, LONG_MIN).evaluate(); + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(LONG_MAX, LONG_MIN).evaluate(); if (call.has_error()) { return false; @@ -287,7 +307,9 @@ inline bool convert::from_string(const char* v, int16_t& dest) noexcept template <> inline bool convert::from_string(const char* v, int8_t& dest) noexcept { - auto call = IOX_POSIX_CALL(strtol)(v, nullptr, STRTOULL_BASE).failureReturnValue(LONG_MAX, LONG_MIN).evaluate(); + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(LONG_MAX, LONG_MIN).evaluate(); if (call.has_error()) { return false; @@ -306,7 +328,9 @@ inline bool convert::from_string(const char* v, int8_t& dest) noexcept template <> inline bool convert::from_string(const char* v, bool& dest) noexcept { - return !IOX_POSIX_CALL(strtoul)(v, nullptr, STRTOULL_BASE) + char* end_ptr = nullptr; + + return !IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(ULONG_MAX) .evaluate() .and_then([&](auto& r) { dest = static_cast(r.value); }) From 80d7830fe537f7c177b5de2b13f6428a7fee6db1 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Tue, 12 Dec 2023 21:27:25 +0800 Subject: [PATCH 04/33] iox-#2055 Add `suppressErrorMessagesForErrnos` Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.inl | 76 ++++++++++++------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index d290408ed4..55f4ad896e 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -96,11 +96,10 @@ inline bool convert::from_string(const char* v, float& dest) noexcept { char* end_ptr = nullptr; - return !IOX_POSIX_CALL(strtof)(v, &end_ptr) - .failureReturnValue(HUGE_VALF, -HUGE_VALF) - .evaluate() - .and_then([&](auto& r) { dest = r.value; }) - .has_error(); + auto call = IOX_POSIX_CALL(strtof)(v, &end_ptr) + .failureReturnValue(HUGE_VALF, -HUGE_VALF) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); } template <> @@ -108,11 +107,10 @@ inline bool convert::from_string(const char* v, double& dest) noexcept { char* end_ptr = nullptr; - return !IOX_POSIX_CALL(strtod)(v, &end_ptr) - .failureReturnValue(HUGE_VAL, -HUGE_VAL) - .evaluate() - .and_then([&](auto& r) { dest = r.value; }) - .has_error(); + auto call = IOX_POSIX_CALL(strtod)(v, &end_ptr) + .failureReturnValue(HUGE_VAL, -HUGE_VAL) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); } template <> @@ -120,11 +118,10 @@ inline bool convert::from_string(const char* v, long double& dest) { char* end_ptr = nullptr; - return !IOX_POSIX_CALL(strtold)(v, &end_ptr) - .failureReturnValue(HUGE_VALL, -HUGE_VALL) - .evaluate() - .and_then([&](auto& r) { dest = r.value; }) - .has_error(); + auto call = IOX_POSIX_CALL(strtold)(v, &end_ptr) + .failureReturnValue(HUGE_VALL, -HUGE_VALL) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); } template <> @@ -132,7 +129,10 @@ inline bool convert::from_string(const char* v, uint64_t& dest) noexce { char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(ULLONG_MAX).evaluate(); + auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(ULLONG_MAX) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); if (call.has_error()) { @@ -180,7 +180,10 @@ inline bool convert::from_string(const char* v, uint32_t& dest) noexce { char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(ULLONG_MAX).evaluate(); + auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(ULLONG_MAX) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); if (call.has_error()) { @@ -202,7 +205,10 @@ inline bool convert::from_string(const char* v, uint16_t& dest) noexce { char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(ULONG_MAX).evaluate(); + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(ULONG_MAX) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); if (call.has_error()) { @@ -224,7 +230,10 @@ inline bool convert::from_string(const char* v, uint8_t& dest) noexcept { char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(ULONG_MAX).evaluate(); + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(ULONG_MAX) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); if (call.has_error()) { @@ -246,7 +255,10 @@ inline bool convert::from_string(const char* v, int64_t& dest) noexcept { char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(LLONG_MAX, LLONG_MIN).evaluate(); + auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(LLONG_MAX, LLONG_MIN) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); if (call.has_error()) { return false; @@ -267,7 +279,10 @@ inline bool convert::from_string(const char* v, int32_t& dest) noexcept { char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(LLONG_MAX, LLONG_MIN).evaluate(); + auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(LLONG_MAX, LLONG_MIN) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); if (call.has_error()) { return false; @@ -288,7 +303,10 @@ inline bool convert::from_string(const char* v, int16_t& dest) noexcept { char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(LONG_MAX, LONG_MIN).evaluate(); + auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(LONG_MAX, LONG_MIN) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); if (call.has_error()) { return false; @@ -309,7 +327,10 @@ inline bool convert::from_string(const char* v, int8_t& dest) noexcept { char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE).failureReturnValue(LONG_MAX, LONG_MIN).evaluate(); + auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(LONG_MAX, LONG_MIN) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); if (call.has_error()) { return false; @@ -330,11 +351,10 @@ inline bool convert::from_string(const char* v, bool& dest) noexcept { char* end_ptr = nullptr; - return !IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) - .failureReturnValue(ULONG_MAX) - .evaluate() - .and_then([&](auto& r) { dest = static_cast(r.value); }) - .has_error(); + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(ULONG_MAX) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); } } // namespace iox From d5043a5f83e1adbeb9cd18cba3686ccfbbf30c1f Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 04:46:17 +0800 Subject: [PATCH 05/33] iox-#2055 Update from_string API for numeric conversion Remove dest for numeric conversion. Now, the part of `for_string` will return iox::optional. Also, we introduce `validate_return_value` and `check_edge_case` to simplify the code of checking. The former can be used to return an iox::optional object while the latter is used in the former to check whether any conversion failure happened. Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 24 ++ .../utility/include/iox/detail/convert.inl | 234 +++++++++--------- 2 files changed, 140 insertions(+), 118 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index dd9cea88d1..2e228bee6d 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -83,6 +83,14 @@ class convert template static bool from_string(const char* v, Destination& dest) noexcept; + /// @todo iox-#2055 + /// @brief for those not Destination not string + /// @tparam Destination + /// @param v + /// @return + template + static iox::optional from_string(const char* v) noexcept; + /// @brief Sets dest from a given string. If the conversion fails false is /// returned and the value of dest is undefined. /// @param[in] v string which contains the value of dest @@ -90,6 +98,22 @@ class convert /// @return false = if the conversion fails otherwise true template static bool from_string(const char* v, string& dest) noexcept; + + private: + /// @todo iox-#2055 + /// @brief Check the edge cases. If + /// @tparam Destination + /// @param errno_cache + /// @param end_ptr + /// @param v + /// @param check_value + /// @return + template + static bool check_edge_case(int errno_cache, const char* end_ptr, const char* v, const Destination& check_value); + + template + static iox::optional + validate_return_value(CallType& call, int errno_cache, const char* end_ptr, const char* v); }; } // namespace iox diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 55f4ad896e..027fc60c93 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -92,41 +92,68 @@ inline bool convert::from_string(const char* v, string& dest) noexcept } template <> -inline bool convert::from_string(const char* v, float& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + // we should clean errno first + errno = 0; + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(ULONG_MAX) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); + + // we assume that in the IOX_POSIX_CALL procedure, no other POSIX call will change errno, + // except for the target function 'f'. + return validate_return_value(call, errno, end_ptr, v); +} + +template <> +inline iox::optional convert::from_string(const char* v) noexcept +{ + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtof)(v, &end_ptr) .failureReturnValue(HUGE_VALF, -HUGE_VALF) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); + + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, double& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtod)(v, &end_ptr) .failureReturnValue(HUGE_VAL, -HUGE_VAL) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); + + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, long double& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtold)(v, &end_ptr) .failureReturnValue(HUGE_VALL, -HUGE_VALL) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); + + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, uint64_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) @@ -134,31 +161,22 @@ inline bool convert::from_string(const char* v, uint64_t& dest) noexce .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - if (call.has_error()) - { - return false; - } - - if (call->value > std::numeric_limits::max()) - { - IOX_LOG(DEBUG, call->value << " too large, uint64_t overflow"); - return false; - } - - dest = static_cast(call->value); - return true; + return validate_return_value(call, errno, end_ptr, v); } #ifdef __APPLE__ /// introduced for mac os since unsigned long is not uint64_t despite it has the same size /// who knows why ¯\_(ツ)_/¯ template <> -inline bool convert::from_string(const char* v, unsigned long& dest) noexcept +inline iox::optional convert::from_string(const char* v, unsigned long& dest) noexcept { uint64_t temp{0}; - bool retVal = from_string(v, temp); - dest = temp; - return retVal; + auto ret = from_string(v, temp); + if (!ret.has_value()) + { + return iox::optional{}; + } + return iox::optional{static_cast(ret.value())}; } #endif @@ -166,18 +184,23 @@ inline bool convert::from_string(const char* v, unsigned long& de /// introduced for 32-bit arm-none-eabi-gcc since uintptr_t is not uint32_t despite it has the same size /// who knows why ¯\_(ツ)_/¯ template <> -inline bool convert::from_string(const char* v, uintptr_t& dest) noexcept +inline iox::optional convert::from_string(const char* v, uintptr_t& dest) noexcept { + // should this be uin32_t? uint64_t temp{0}; - bool retVal = from_string(v, temp); - dest = temp; - return retVal; + auto ret = from_string(v, temp); + if (!ret.has_value()) + { + return iox::optional{}; + } + return iox::optional{static_cast(ret.value())}; } #endif template <> -inline bool convert::from_string(const char* v, uint32_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) @@ -185,24 +208,13 @@ inline bool convert::from_string(const char* v, uint32_t& dest) noexce .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - if (call.has_error()) - { - return false; - } - - if (call->value > std::numeric_limits::max()) - { - IOX_LOG(DEBUG, call->value << " too large, uint32_t overflow"); - return false; - } - - dest = static_cast(call->value); - return true; + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, uint16_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) @@ -210,24 +222,13 @@ inline bool convert::from_string(const char* v, uint16_t& dest) noexce .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - if (call.has_error()) - { - return false; - } - - if (call->value > std::numeric_limits::max()) - { - IOX_LOG(DEBUG, call->value << " too large, uint16_t overflow"); - return false; - } - - dest = static_cast(call->value); - return true; + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, uint8_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) @@ -235,126 +236,123 @@ inline bool convert::from_string(const char* v, uint8_t& dest) noexcept .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - if (call.has_error()) - { - return false; - } - - if (call->value > std::numeric_limits::max()) - { - IOX_LOG(DEBUG, call->value << " too large, uint8_t overflow"); - return false; - } - - dest = static_cast(call->value); - return true; + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, int64_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(LLONG_MAX, LLONG_MIN) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - if (call.has_error()) - { - return false; - } - if (call->value > std::numeric_limits::max() || call->value < std::numeric_limits::min()) - { - IOX_LOG(DEBUG, call->value << " is out of range, int64_t overflow"); - return false; - } - - dest = static_cast(call->value); - return true; + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, int32_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(LLONG_MAX, LLONG_MIN) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - if (call.has_error()) - { - return false; - } - if (call->value > std::numeric_limits::max() || call->value < std::numeric_limits::min()) - { - IOX_LOG(DEBUG, call->value << " is out of range, int32_t overflow"); - return false; - } - - dest = static_cast(call->value); - return true; + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, int16_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(LONG_MAX, LONG_MIN) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - if (call.has_error()) - { - return false; - } - if (call->value > std::numeric_limits::max() || call->value < std::numeric_limits::min()) - { - IOX_LOG(DEBUG, call->value << " is out of range, int16_t overflow"); - return false; - } - - dest = static_cast(call->value); - return true; + return validate_return_value(call, errno, end_ptr, v); } template <> -inline bool convert::from_string(const char* v, int8_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { + errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(LONG_MAX, LONG_MIN) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - if (call.has_error()) + + return validate_return_value(call, errno, end_ptr, v); +} + +template +inline bool +convert::check_edge_case(int errno_cache, const char* end_ptr, const char* v, const Destination& check_value) +{ + // invalid string + if (v == end_ptr && check_value == 0) { + IOX_LOG(DEBUG, "invalid input"); return false; } - if (call->value > std::numeric_limits::max() || call->value < std::numeric_limits::min()) + // end_ptr is not '\0' which means conversion failure at end_ptr + if (end_ptr != nullptr && v != end_ptr && *end_ptr != '\0') { - IOX_LOG(DEBUG, call->value << " is out of range, int8_t overflow"); + // can split and reconvert here? wait for implement later + IOX_LOG(DEBUG, "conversion failed at " << end_ptr - v << " : " << *end_ptr); return false; } - dest = static_cast(call->value); + if constexpr (std::is_arithmetic_v) + { + // out of range (upper bound) + if (errno_cache == ERANGE && check_value > std::numeric_limits::max()) + { + IOX_LOG(DEBUG, + check_value << " is out of range (upper bound), should be less than " + << std::numeric_limits::max()); + return false; + } + + // out of range (lower bound) + if (errno_cache == ERANGE && check_value < std::numeric_limits::min()) + { + IOX_LOG(DEBUG, + check_value << " is out of range (lower bound), should be larger than " + << std::numeric_limits::min()); + return false; + } + } + return true; } -template <> -inline bool convert::from_string(const char* v, bool& dest) noexcept +template +inline iox::optional +convert::validate_return_value(CallType& call, int errno_cache, const char* end_ptr, const char* v) { - char* end_ptr = nullptr; + if (call.has_error()) + { + return iox::optional{}; + } - auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) - .failureReturnValue(ULONG_MAX) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) - .evaluate(); + if (!check_edge_case(errno_cache, end_ptr, v, call->value)) + { + return iox::optional{}; + } + + return iox::optional(static_cast(call->value)); } } // namespace iox From 1082cc527a287b86f16fdfa41425ef182939675a Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 04:52:12 +0800 Subject: [PATCH 06/33] iox-#2055 Rename to `evaluate_return_value` Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 2 +- .../utility/include/iox/detail/convert.inl | 26 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index 2e228bee6d..c3fe5ad879 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -113,7 +113,7 @@ class convert template static iox::optional - validate_return_value(CallType& call, int errno_cache, const char* end_ptr, const char* v); + evaluate_return_value(CallType& call, int errno_cache, const char* end_ptr, const char* v); }; } // namespace iox diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 027fc60c93..b80800abb6 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -105,7 +105,7 @@ inline iox::optional convert::from_string(const char* v) noexcept // we assume that in the IOX_POSIX_CALL procedure, no other POSIX call will change errno, // except for the target function 'f'. - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -119,7 +119,7 @@ inline iox::optional convert::from_string(const char* v) noexcept .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -133,7 +133,7 @@ inline iox::optional convert::from_string(const char* v) noexcep .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -147,7 +147,7 @@ inline iox::optional convert::from_string(const char* .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -161,7 +161,7 @@ inline iox::optional convert::from_string(const char* v) noe .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } #ifdef __APPLE__ @@ -208,7 +208,7 @@ inline iox::optional convert::from_string(const char* v) noe .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -222,7 +222,7 @@ inline iox::optional convert::from_string(const char* v) noe .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -236,7 +236,7 @@ inline iox::optional convert::from_string(const char* v) noexc .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -250,7 +250,7 @@ inline iox::optional convert::from_string(const char* v) noexc .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -264,7 +264,7 @@ inline iox::optional convert::from_string(const char* v) noexc .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -278,7 +278,7 @@ inline iox::optional convert::from_string(const char* v) noexc .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> @@ -292,7 +292,7 @@ inline iox::optional convert::from_string(const char* v) noexcep .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return validate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template @@ -340,7 +340,7 @@ convert::check_edge_case(int errno_cache, const char* end_ptr, const char* v, co template inline iox::optional -convert::validate_return_value(CallType& call, int errno_cache, const char* end_ptr, const char* v) +convert::evaluate_return_value(CallType& call, int errno_cache, const char* end_ptr, const char* v) { if (call.has_error()) { From 27b0562b214c28207e23f50a4d16fb61465b0856 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 06:31:49 +0800 Subject: [PATCH 07/33] iox-#2055 Modify from_string API The from_string API has been updated. It now returns an iox::optional of the specified target value type, and the dest parameter has been removed. Subsequently, functions that utilize from_string have been restructured to accommodate the new calling format. Some of these functions now require default values for the value_or method, but I am uncertain whether these default values are appropriate. A new function named forceOkReturnValue has been introduced (the name may be subject to change later). This function addresses a specific issue encountered with uint64_t cases. Previously, we used failureReturnValue(ULLONG_MAX), which incorrectly flagged the valid conversion case of "18446744073709551615" as a failure. With forceOkReturnValue, the condition call.has_error() should consistently return false for this scenario. The accuracy of the conversion result is now assessed within the check_edge_case function. As a note, areas marked with @todo iox-#2055 still require modifications, most of which pertain to documentation. These will be addressed in the upcoming commit. Signed-off-by: Dennis Liu --- iceoryx_examples/iceperf/main_follower.cpp | 6 +- iceoryx_examples/iceperf/main_leader.cpp | 6 +- .../design/include/iox/detail/posix_call.inl | 7 + .../posix/design/include/iox/posix_call.hpp | 6 + .../test/moduletests/test_utility_convert.cpp | 220 +++++++----------- .../utility/include/iox/detail/convert.hpp | 94 ++++++-- .../utility/include/iox/detail/convert.inl | 220 ++++++++++++++---- .../include/iox/detail/serialization.inl | 21 +- .../runtime/ipc_runtime_interface.hpp | 3 +- iceoryx_posh/source/roudi/port_manager.cpp | 10 +- iceoryx_posh/source/roudi/process_manager.cpp | 6 +- iceoryx_posh/source/roudi/roudi.cpp | 12 +- .../source/roudi/roudi_cmd_line_parser.cpp | 27 ++- .../source/runtime/ipc_interface_base.cpp | 20 +- .../source/runtime/ipc_runtime_interface.cpp | 40 +++- .../source/runtime/posh_runtime_impl.cpp | 116 +++++++-- .../source/introspection_app.cpp | 13 +- 17 files changed, 571 insertions(+), 256 deletions(-) diff --git a/iceoryx_examples/iceperf/main_follower.cpp b/iceoryx_examples/iceperf/main_follower.cpp index f9b5a1e0d9..04e055e6b1 100644 --- a/iceoryx_examples/iceperf/main_follower.cpp +++ b/iceoryx_examples/iceperf/main_follower.cpp @@ -48,11 +48,15 @@ int main(int argc, char* argv[]) constexpr decltype(EXIT_SUCCESS) MOO{EXIT_SUCCESS}; uint64_t intensity{0U}; - if (!iox::convert::from_string(optarg, intensity)) + auto result = iox::convert::from_string(optarg); + if (!result.has_value()) { std::cerr << "Could not parse 'intensity' paramater!" << std::endl; return EXIT_FAILURE; } + + intensity = result.value(); + if (intensity > 100) { std::cerr << "Too high moo 'intensity'!" << std::endl; diff --git a/iceoryx_examples/iceperf/main_leader.cpp b/iceoryx_examples/iceperf/main_leader.cpp index 6e72b00833..2b4300f5a6 100644 --- a/iceoryx_examples/iceperf/main_leader.cpp +++ b/iceoryx_examples/iceperf/main_leader.cpp @@ -116,12 +116,16 @@ int main(int argc, char* argv[]) } break; case 'n': - if (!iox::convert::from_string(optarg, settings.numberOfSamples)) + { + auto result = iox::convert::from_string(optarg); + if (!result.has_value()) { std::cerr << "Could not parse 'number-of-samples' paramater!" << std::endl; return EXIT_FAILURE; } + settings.numberOfSamples = result.value(); break; + } default: return EXIT_FAILURE; }; diff --git a/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl b/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl index 5c9ccf135c..82c89b07fb 100644 --- a/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl +++ b/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl @@ -146,6 +146,13 @@ inline PosixCallEvaluator PosixCallVerificator::returnVa return PosixCallEvaluator(m_details); } +template +inline PosixCallEvaluator PosixCallVerificator::forceOkReturnValue() && noexcept +{ + m_details.hasSuccess = true; + return PosixCallEvaluator(m_details); +} + template inline PosixCallEvaluator::PosixCallEvaluator(detail::PosixCallDetails& details) noexcept : m_details{details} diff --git a/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp b/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp index 4a950d47cb..9edaff9205 100644 --- a/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp +++ b/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp @@ -132,6 +132,12 @@ class [[nodiscard]] PosixCallVerificator /// @return the PosixCallEvaluator which evaluates the errno values PosixCallEvaluator returnValueMatchesErrno() && noexcept; + /// @todo iox-#2055: from_string requires a method to return a never failed + /// (has_error() == false) PosixCallEvaluator. + /// @brief + /// @return + PosixCallEvaluator forceOkReturnValue() && noexcept; + private: template friend class PosixCallBuilder; diff --git a/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp b/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp index dd783877c6..0117a7bac3 100644 --- a/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp +++ b/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved. // Copyright (c) 2021 - 2022 by Apex.AI Inc. All rights reserved. // Copyright (c) 2022 by NXP. All rights reserved. +// Copyright (c) 2023 by Dennis Liu. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -108,323 +109,266 @@ TEST_F(convert_test, FromString_String) { ::testing::Test::RecordProperty("TEST_ID", "22463da5-0fcb-4aa2-a7e5-68b863278a81"); std::string source = "hello"; - std::string destination; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(source, Eq(destination)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(source)); } TEST_F(convert_test, fromString_Char_Success) { ::testing::Test::RecordProperty("TEST_ID", "a15825c9-536a-4671-a502-6973490022e7"); std::string source = "h"; - char destination = '\0'; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(source[0], Eq(destination)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(source[0])); } TEST_F(convert_test, fromString_Char_Fail) { ::testing::Test::RecordProperty("TEST_ID", "656e87ad-6fdb-42d7-bf49-23f81a4f5a31"); std::string source = "hasd"; - char destination = '\0'; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); -} - -TEST_F(convert_test, stringIsNumber_IsINTEGER) -{ - ::testing::Test::RecordProperty("TEST_ID", "d3961dde-2e76-4e8d-b448-d1ad0f734ab1"); - EXPECT_THAT(iox::convert::stringIsNumber("123921301", NumberType::INTEGER), Eq(true)); -} - -TEST_F(convert_test, stringIsNumber_IsEmpty) -{ - ::testing::Test::RecordProperty("TEST_ID", "1cdf0515-e021-4df1-ac08-b0f2b366097c"); - EXPECT_THAT(iox::convert::stringIsNumber("", NumberType::INTEGER), Eq(false)); -} - -TEST_F(convert_test, stringIsNumber_IsZero) -{ - ::testing::Test::RecordProperty("TEST_ID", "f36cbb74-35fc-4a2b-b6b4-8bea810dcf3f"); - EXPECT_THAT(iox::convert::stringIsNumber("0", NumberType::INTEGER), Eq(true)); -} - -TEST_F(convert_test, stringIsNumber_INTEGERWithSign) -{ - ::testing::Test::RecordProperty("TEST_ID", "af9e7aeb-b6c5-440d-a706-e869dd8454f3"); - EXPECT_THAT(iox::convert::stringIsNumber("-521", NumberType::INTEGER), Eq(true)); -} - -TEST_F(convert_test, stringIsNumber_INTEGERWithSignPlacedWrongly) -{ - ::testing::Test::RecordProperty("TEST_ID", "32cc349b-baaf-4128-97c9-da3687097f4b"); - EXPECT_THAT(iox::convert::stringIsNumber("2-3", NumberType::UNSIGNED_INTEGER), Eq(false)); -} - -TEST_F(convert_test, stringIsNumber_SimpleFLOAT) -{ - ::testing::Test::RecordProperty("TEST_ID", "34407449-1eed-440d-be9e-f8d25ddd700e"); - EXPECT_THAT(iox::convert::stringIsNumber("123.456", NumberType::FLOAT), Eq(true)); -} - -TEST_F(convert_test, stringIsNumber_MultiDotFLOAT) -{ - ::testing::Test::RecordProperty("TEST_ID", "d6ae9709-0fe5-472f-a786-90a4cc11db6a"); - EXPECT_THAT(iox::convert::stringIsNumber("11.1.123", NumberType::FLOAT), Eq(false)); -} - -TEST_F(convert_test, stringIsNumber_FLOATWithSign) -{ - ::testing::Test::RecordProperty("TEST_ID", "c840aa92-aab7-4d01-a6ce-d722bd1296dd"); - EXPECT_THAT(iox::convert::stringIsNumber("+123.321", NumberType::FLOAT), Eq(true)); -} - -TEST_F(convert_test, stringIsNumber_NumberWithLetters) -{ - ::testing::Test::RecordProperty("TEST_ID", "2039f8e9-70f7-451c-9415-287269e97f83"); - EXPECT_THAT(iox::convert::stringIsNumber("+123a.123", NumberType::FLOAT), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_FLOAT_Success) { ::testing::Test::RecordProperty("TEST_ID", "d6255c3e-369e-43a0-a1ab-03f7b13d03c2"); std::string source = "123.01"; - float destination = 0.0F; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_FLOAT_EQ(destination, 123.01F); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_FLOAT_EQ(result.value(), 123.01F); } TEST_F(convert_test, fromString_FLOAT_Fail) { ::testing::Test::RecordProperty("TEST_ID", "e2b94d50-664c-4f9e-be4f-99212c6fa165"); std::string source = "hasd"; - float destination = 0.0F; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_Double_Success) { ::testing::Test::RecordProperty("TEST_ID", "95ba379e-120e-4b80-a829-33fe54f1bfed"); std::string source = "123.04"; - double destination = 0.0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(destination, Eq(123.04)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), DoubleEq(123.04)); } TEST_F(convert_test, fromString_Double_Fail) { ::testing::Test::RecordProperty("TEST_ID", "f4ace11b-a056-47b1-b6c5-6fb2c58e1a06"); std::string source = "hasd"; - double destination = 0.0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_LongDouble_Success) { ::testing::Test::RecordProperty("TEST_ID", "2864fbae-ef1c-48ab-97f2-745baadc4dc5"); std::string source = "121.01"; - long double destination = 0.0; constexpr long double VERIFY = 121.01; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(static_cast(destination), DoubleEq(static_cast(VERIFY))); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(static_cast(result.value()), DoubleEq(static_cast(VERIFY))); } TEST_F(convert_test, fromString_LongDouble_Fail) { ::testing::Test::RecordProperty("TEST_ID", "519f2ac5-8836-419e-8034-377230a88a09"); std::string source = "hasd"; - double destination = 0.0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_UNSIGNED_Int_Success) { ::testing::Test::RecordProperty("TEST_ID", "1edb8d5f-c42d-4d02-bc31-477f48898bbb"); std::string source = "100"; - unsigned int destination = 0.0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(destination, Eq(100U)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(100U)); } TEST_F(convert_test, fromString_UNSIGNED_Int_Fail) { ::testing::Test::RecordProperty("TEST_ID", "6ce6de82-a6c0-4562-9c5c-663b93d768b3"); std::string source = "-331"; - unsigned int destination = 0U; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_UNSIGNED_LongInt_Success) { ::testing::Test::RecordProperty("TEST_ID", "054b08b2-54e1-4191-91b6-e6bec415612f"); std::string source = "999"; - uint64_t destination = 0U; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(destination, Eq(999LU)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(999LU)); } TEST_F(convert_test, fromString_UNSIGNED_LongInt_Fail) { ::testing::Test::RecordProperty("TEST_ID", "4b215747-90b2-4ca2-97ee-517c07597b1b"); std::string source = "-a123"; - uint64_t destination = 0U; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_Int_Success) { ::testing::Test::RecordProperty("TEST_ID", "9318ee60-f2e0-445a-b32d-c718cf918b18"); std::string source = "3331"; - int destination = 0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(destination, Eq(3331)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(3331)); } TEST_F(convert_test, fromString_Int_Fail) { ::testing::Test::RecordProperty("TEST_ID", "f8e698a9-054d-4441-b196-bcd58a72b1d9"); std::string source = "-+321"; - int destination = 0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_ShortInt_Success) { ::testing::Test::RecordProperty("TEST_ID", "e804f821-157d-4c52-81a7-75fce5a43805"); std::string source = "12345"; - short destination = 0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(destination, Eq(12345)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(12345)); } TEST_F(convert_test, fromString_ShortInt_Fail) { ::testing::Test::RecordProperty("TEST_ID", "1150066b-cb42-4055-9927-2f20fb40bc87"); std::string source = "-+123321"; - short destination = 0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_Bool_Success) { ::testing::Test::RecordProperty("TEST_ID", "893723fc-dfb8-46a4-b446-badaf8bad25a"); std::string source = "1"; - bool destination = false; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(destination, Eq(true)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(true)); } TEST_F(convert_test, fromString_Bool_Fail) { ::testing::Test::RecordProperty("TEST_ID", "1c937da6-29ea-49cf-a7d0-4c46f564c16e"); std::string source = "-+222"; - bool destination = false; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_UShortInt_Success) { ::testing::Test::RecordProperty("TEST_ID", "99d22d80-3860-47fa-9f98-f11ff9629815"); std::string source = "333"; - unsigned short destination = 0U; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(destination, Eq(333)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(333)); } TEST_F(convert_test, fromString_UShortInt_Fail) { ::testing::Test::RecordProperty("TEST_ID", "6ab6ded6-dff3-401a-8a7f-98326da7cca6"); std::string source = "-+111"; - unsigned short destination = 0U; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_LongInt_Success) { ::testing::Test::RecordProperty("TEST_ID", "37133256-ae79-45c7-8c86-56bd33fa7bd8"); std::string source = "-1123"; - int64_t destination = 0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); - EXPECT_THAT(destination, Eq(-1123L)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(true)); + EXPECT_THAT(result.value(), Eq(-1123L)); } TEST_F(convert_test, fromString_LongInt_Fail) { ::testing::Test::RecordProperty("TEST_ID", "0e368bf3-cb16-4829-a4cc-dc56e0bde958"); std::string source = "-a121"; - int64_t destination = 0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + auto result = iox::convert::from_string(source.c_str()); + EXPECT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_MinMaxShort) { ::testing::Test::RecordProperty("TEST_ID", "98e33efd-ba39-4b88-8307-358be30e4e73"); std::string source = "32767"; - int16_t destination = 0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + auto gg = iox::convert::from_string(source.c_str()); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(true)); source = "32768"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(false)); source = "-32768"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(true)); source = "-32769"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(false)); } TEST_F(convert_test, fromString_MinMaxUNSIGNED_Short) { ::testing::Test::RecordProperty("TEST_ID", "f9196939-ae5d-4c27-85bf-b3b084343261"); std::string source = "65535"; - uint16_t destination = 0U; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(true)); source = "65536"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(false)); source = "0"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(true)); source = "-1"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(false)); } TEST_F(convert_test, fromString_MinMaxInt) { ::testing::Test::RecordProperty("TEST_ID", "abf0fda5-044e-4f1b-bb1e-31b701578a3d"); std::string source = "2147483647"; - int32_t destination = 0; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(true)); source = "2147483648"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(false)); source = "-2147483648"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(true)); source = "-2147483649"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(false)); } TEST_F(convert_test, fromString_MinMaxUNSIGNED_Int) { ::testing::Test::RecordProperty("TEST_ID", "c2a832ef-3e86-4303-a98c-63c7b11ea789"); std::string source = "4294967295"; - uint32_t destination = 0U; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(true)); source = "4294967296"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(false)); source = "0"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(true)); source = "-1"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string(source.c_str()).has_value(), Eq(false)); } TEST_F(convert_test, fromString_cxxString) { ::testing::Test::RecordProperty("TEST_ID", "dbf015bb-5f51-47e1-9d0e-0525f65e7803"); std::string source = "hello"; - iox::string<8> destination; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + constexpr uint64_t STRING_CAPACITY{8}; + EXPECT_THAT(iox::convert::from_string>(source.c_str()).has_value(), Eq(true)); source = ""; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string>(source.c_str()).has_value(), Eq(true)); source = "12345678"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(true)); + EXPECT_THAT(iox::convert::from_string>(source.c_str()).has_value(), Eq(true)); source = "123456789"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string>(source.c_str()).has_value(), Eq(false)); source = "this_is_a_very_long_string"; - EXPECT_THAT(iox::convert::from_string(source.c_str(), destination), Eq(false)); + EXPECT_THAT(iox::convert::from_string>(source.c_str()).has_value(), Eq(false)); } } // namespace diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index c3fe5ad879..b3f78c0d61 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -1,6 +1,7 @@ // Copyright (c) 2019, 2021 by Robert Bosch GmbH. All rights reserved. // Copyright (c) 2021 by Apex.AI Inc. All rights reserved. // Copyright (c) 2022 by NXP. All rights reserved. +// Copyright (c) 2023 by Dennis Liu. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -80,26 +81,30 @@ class convert /// @param[in] v string which contains the value of dest /// @param[in] dest destination to which the value should be written /// @return false = if the conversion fails otherwise true - template - static bool from_string(const char* v, Destination& dest) noexcept; + template ::value, int> = 0> + static iox::optional from_string(const char* v) noexcept; - /// @todo iox-#2055 /// @brief for those not Destination not string /// @tparam Destination /// @param v /// @return - template + template ::value, int> = 0> static iox::optional from_string(const char* v) noexcept; - /// @brief Sets dest from a given string. If the conversion fails false is - /// returned and the value of dest is undefined. - /// @param[in] v string which contains the value of dest - /// @param[in] dest destination to which the value should be written - /// @return false = if the conversion fails otherwise true - template - static bool from_string(const char* v, string& dest) noexcept; - private: + /// @todo iox-#2055 + /// @brief + /// @tparam ValueType + /// @tparam CallType + /// @param call + /// @param errno_cache + /// @param end_ptr + /// @param v + /// @return + template + static iox::optional + evaluate_return_value(CallType& call, decltype(errno) errno_cache, const char* end_ptr, const char* v) noexcept; + /// @todo iox-#2055 /// @brief Check the edge cases. If /// @tparam Destination @@ -108,12 +113,67 @@ class convert /// @param v /// @param check_value /// @return - template - static bool check_edge_case(int errno_cache, const char* end_ptr, const char* v, const Destination& check_value); + template + static bool check_edge_case(decltype(errno) errno_cache, + const char* end_ptr, + const char* v, + const RequireCheckValType& require_check_val) noexcept; + + /// @todo iox-#2055 + /// @brief + /// @param v + /// @return + static bool start_with_neg_sign(const char* v) noexcept; + + /// @todo iox-#2055 + /// @brief + /// @tparam RequireCheckValType + /// @param end_ptr + /// @param v + /// @param require_check_val + /// @return + template + static bool + is_valid_input(const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept; - template - static iox::optional - evaluate_return_value(CallType& call, int errno_cache, const char* end_ptr, const char* v); + + /// @todo iox-#2055 + /// @brief + /// @param errno_cache + /// @return + static bool is_valid_errno(decltype(errno) errno_cache) noexcept; + + + /// @todo iox-#2055 + /// @brief + /// @tparam TargetType + /// @tparam RequireCheckValType + /// @param require_check_val + /// @return + template + static bool is_within_range(const RequireCheckValType& require_check_val) noexcept; + + + /// @todo iox-#2055 helper, I believe there's a more elegant way to implement this. + private: + template + struct is_iox_string : std::false_type + { + }; + + template + struct is_iox_string> : std::true_type + { + }; + + template + struct GetCapacity; + + template + struct GetCapacity> + { + static constexpr uint64_t value = Capacity; + }; }; } // namespace iox diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index b80800abb6..778ab462e3 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -1,6 +1,7 @@ // Copyright (c) 2019, 2021 by Robert Bosch GmbH. All rights reserved. // Copyright (c) 2021 - 2022 by Apex.AI Inc. All rights reserved. // Copyright (c) 2022 by NXP. All rights reserved. +// Copyright (c) 2023 by Dennis Liu. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -57,38 +58,34 @@ convert::toString(const Source& t) noexcept return t; } -template -inline bool convert::from_string(const char* v, Destination& dest) noexcept +template ::value, int>> +inline iox::optional convert::from_string(const char* v) noexcept { - dest = Destination(v); - return true; + return iox::optional(Destination(v)); } template <> -inline bool convert::from_string(const char* v, char& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { if (strlen(v) != 1U) { IOX_LOG(DEBUG, v << " is not a char"); - return false; + return iox::nullopt; } /// @NOLINTJUSTIFICATION encapsulated in abstraction /// @NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - dest = v[0]; - return true; + return iox::optional(v[0]); } -template -inline bool convert::from_string(const char* v, string& dest) noexcept +template ::value, int>> +inline iox::optional convert::from_string(const char* v) noexcept { - if (strlen(v) > Capacity) + if (strlen(v) > GetCapacity::value) { - return false; + return iox::nullopt; } - - dest = string(TruncateToCapacity, v); - return true; + return iox::optional(IoxString(TruncateToCapacity, v)); } template <> @@ -98,6 +95,11 @@ inline iox::optional convert::from_string(const char* v) noexcept errno = 0; char* end_ptr = nullptr; + if (start_with_neg_sign(v)) + { + return iox::nullopt; + } + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(ULONG_MAX) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) @@ -156,8 +158,13 @@ inline iox::optional convert::from_string(const char* v) noe errno = 0; char* end_ptr = nullptr; + if (start_with_neg_sign(v)) + { + return iox::nullopt; + } + auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) - .failureReturnValue(ULLONG_MAX) + .forceOkReturnValue() .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -186,7 +193,6 @@ inline iox::optional convert::from_string(const ch template <> inline iox::optional convert::from_string(const char* v, uintptr_t& dest) noexcept { - // should this be uin32_t? uint64_t temp{0}; auto ret = from_string(v, temp); if (!ret.has_value()) @@ -203,6 +209,11 @@ inline iox::optional convert::from_string(const char* v) noe errno = 0; char* end_ptr = nullptr; + if (start_with_neg_sign(v)) + { + return iox::nullopt; + } + auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(ULLONG_MAX) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) @@ -217,6 +228,11 @@ inline iox::optional convert::from_string(const char* v) noe errno = 0; char* end_ptr = nullptr; + if (start_with_neg_sign(v)) + { + return iox::nullopt; + } + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(ULONG_MAX) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) @@ -231,6 +247,11 @@ inline iox::optional convert::from_string(const char* v) noexc errno = 0; char* end_ptr = nullptr; + if (start_with_neg_sign(v)) + { + return iox::nullopt; + } + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(ULONG_MAX) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) @@ -295,12 +316,115 @@ inline iox::optional convert::from_string(const char* v) noexcep return evaluate_return_value(call, errno, end_ptr, v); } -template +inline bool convert::start_with_neg_sign(const char* v) noexcept +{ + if (v == nullptr) + { + return false; + } + + // remove space + while (*v != '\0' && (isspace((unsigned char)*v) != 0)) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + v++; + } + + return (*v == '-'); +} + +// template +// inline bool convert::check_edge_case(decltype(errno) errno_cache, +// const char* end_ptr, +// const char* v, +// const RequireCheckValType& require_check_val) +// { +// // invalid string +// if (v == end_ptr && require_check_val == 0) +// { +// IOX_LOG(DEBUG, "invalid input"); +// return false; +// } + +// // end_ptr is not '\0' which means conversion failure at end_ptr +// if (end_ptr != nullptr && v != end_ptr && *end_ptr != '\0') +// { +// // can split and reconvert here? wait for implement later +// IOX_LOG(DEBUG, "conversion failed at " << end_ptr - v << " : " << *end_ptr); +// return false; +// } + +// // check errno +// if (errno_cache == ERANGE) +// { +// IOX_LOG(DEBUG, "ERANGE triggered during conversion"); +// return false; +// } + +// if (errno_cache == EINVAL) +// { +// IOX_LOG(DEBUG, "EINVAL triggered during conversion"); +// return false; +// } + +// if constexpr (std::is_arithmetic_v) +// { +// // out of range (upper bound) +// if (require_check_val > std::numeric_limits::max()) +// { +// IOX_LOG(DEBUG, +// require_check_val << " is out of range (upper bound), should be less than " +// << std::numeric_limits::max()); +// return false; +// } + +// // out of range (lower bound) +// if (require_check_val < std::numeric_limits::lowest()) +// { +// IOX_LOG(DEBUG, +// require_check_val << " is out of range (lower bound), should be larger than " +// << std::numeric_limits::lowest()); +// return false; +// } +// } + +// return true; +// } + +template +inline bool convert::check_edge_case(decltype(errno) errno_cache, + const char* end_ptr, + const char* v, + const RequireCheckValType& require_check_val) noexcept +{ + return is_valid_input(end_ptr, v, require_check_val) && is_valid_errno(errno_cache) + && is_within_range(require_check_val); +} + +template +inline iox::optional +convert::evaluate_return_value(CallType& call, decltype(errno) errno_cache, const char* end_ptr, const char* v) noexcept +{ + if (call.has_error()) + { + return iox::nullopt; + } + + if (!check_edge_case(errno_cache, end_ptr, v, call->value)) + { + return iox::nullopt; + } + + return iox::optional(static_cast(call->value)); +} + + +template inline bool -convert::check_edge_case(int errno_cache, const char* end_ptr, const char* v, const Destination& check_value) +convert::is_valid_input(const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept { // invalid string - if (v == end_ptr && check_value == 0) + if (v == end_ptr && require_check_val == 0) { IOX_LOG(DEBUG, "invalid input"); return false; @@ -309,28 +433,51 @@ convert::check_edge_case(int errno_cache, const char* end_ptr, const char* v, co // end_ptr is not '\0' which means conversion failure at end_ptr if (end_ptr != nullptr && v != end_ptr && *end_ptr != '\0') { - // can split and reconvert here? wait for implement later IOX_LOG(DEBUG, "conversion failed at " << end_ptr - v << " : " << *end_ptr); return false; } - if constexpr (std::is_arithmetic_v) + return true; +} + +inline bool convert::is_valid_errno(decltype(errno) errno_cache) noexcept +{ + // check errno + if (errno_cache == ERANGE) + { + IOX_LOG(DEBUG, "ERANGE triggered during conversion"); + return false; + } + + if (errno_cache == EINVAL) + { + IOX_LOG(DEBUG, "EINVAL triggered during conversion"); + return false; + } + + return true; +} + +template +inline bool convert::is_within_range(const RequireCheckValType& require_check_val) noexcept +{ + if constexpr (std::is_arithmetic_v) { // out of range (upper bound) - if (errno_cache == ERANGE && check_value > std::numeric_limits::max()) + if (require_check_val > std::numeric_limits::max()) { IOX_LOG(DEBUG, - check_value << " is out of range (upper bound), should be less than " - << std::numeric_limits::max()); + require_check_val << " is out of range (upper bound), should be less than " + << std::numeric_limits::max()); return false; } // out of range (lower bound) - if (errno_cache == ERANGE && check_value < std::numeric_limits::min()) + if (require_check_val < std::numeric_limits::lowest()) { IOX_LOG(DEBUG, - check_value << " is out of range (lower bound), should be larger than " - << std::numeric_limits::min()); + require_check_val << " is out of range (lower bound), should be larger than " + << std::numeric_limits::lowest()); return false; } } @@ -338,23 +485,6 @@ convert::check_edge_case(int errno_cache, const char* end_ptr, const char* v, co return true; } -template -inline iox::optional -convert::evaluate_return_value(CallType& call, int errno_cache, const char* end_ptr, const char* v) -{ - if (call.has_error()) - { - return iox::optional{}; - } - - if (!check_edge_case(errno_cache, end_ptr, v, call->value)) - { - return iox::optional{}; - } - - return iox::optional(static_cast(call->value)); -} - } // namespace iox #endif // IOX_HOOFS_UTILITY_CONVERT_INL diff --git a/iceoryx_hoofs/utility/include/iox/detail/serialization.inl b/iceoryx_hoofs/utility/include/iox/detail/serialization.inl index 9e6789eb6a..61eecb40d7 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/serialization.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/serialization.inl @@ -94,11 +94,14 @@ inline bool Serialization::deserialize(const std::string& serializedString, T& t return false; } - if (!convert::from_string(entry.c_str(), t)) + auto result = convert::from_string(entry.c_str()); + + if (!result.has_value()) { return false; } + t = result.value(); return deserialize(remainder, args...); } @@ -111,11 +114,15 @@ inline bool Serialization::removeFirstEntry(std::string& firstEntry, std::string } uint64_t length{0}; - if (!convert::from_string(remainder.substr(0, pos).c_str(), length)) + auto result = convert::from_string(remainder.substr(0, pos).c_str()); + + if (!result.has_value()) { return false; } + length = result.value(); + if (remainder.size() < pos + length + 1U) { return false; @@ -140,7 +147,15 @@ inline bool Serialization::getNth(const unsigned int index, T& t) const noexcept } } - return convert::from_string(entry.c_str(), t); + auto result = convert::from_string(entry.c_str()); + + if (!result.has_value()) + { + return false; + } + + t = result.value(); + return true; } } // namespace iox diff --git a/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_runtime_interface.hpp b/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_runtime_interface.hpp index abfce81d6d..79a4f356af 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_runtime_interface.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_runtime_interface.hpp @@ -70,7 +70,8 @@ class IpcRuntimeInterface enum class RegAckResult { SUCCESS, - TIMEOUT + TIMEOUT, + CONVERSION_FAILURE }; void waitForRoudi(deadline_timer& timer) noexcept; diff --git a/iceoryx_posh/source/roudi/port_manager.cpp b/iceoryx_posh/source/roudi/port_manager.cpp index 87d64a83ab..389834ac8f 100644 --- a/iceoryx_posh/source/roudi/port_manager.cpp +++ b/iceoryx_posh/source/roudi/port_manager.cpp @@ -32,7 +32,15 @@ namespace roudi capro::Interfaces StringToCaProInterface(const capro::IdString_t& str) noexcept { int32_t i{0}; - convert::from_string(str.c_str(), i); + auto result = convert::from_string(str.c_str()); + if (!result.has_value()) + { + IOX_LOG(WARN, "conversion failure"); + return capro::Interfaces::INTERNAL; + } + + i = result.has_value(); + if (i >= static_cast(capro::Interfaces::INTERFACE_END)) { IOX_LOG(WARN, "invalid enum (out of range: " << i << ")"); diff --git a/iceoryx_posh/source/roudi/process_manager.cpp b/iceoryx_posh/source/roudi/process_manager.cpp index 8165d63200..f1bb436c7c 100644 --- a/iceoryx_posh/source/roudi/process_manager.cpp +++ b/iceoryx_posh/source/roudi/process_manager.cpp @@ -290,9 +290,9 @@ bool ProcessManager::addProcess(const RuntimeName_t& name, } auto heartbeatPoolIndex = HeartbeatPool::Index::INVALID; /// @todo iox-#2055 this workaround is required sind the conversion of edge cases is broken - constexpr uint8_t IOX_2055_WORKAROUND{1}; - iox::UntypedRelativePointer::offset_t heartbeatOffset{iox::UntypedRelativePointer::NULL_POINTER_OFFSET - - IOX_2055_WORKAROUND}; + /// I think it's solved. + iox::UntypedRelativePointer::offset_t heartbeatOffset{iox::UntypedRelativePointer::NULL_POINTER_OFFSET}; + if (isMonitored) { auto heartbeat = m_heartbeatPool->emplace(); diff --git a/iceoryx_posh/source/roudi/roudi.cpp b/iceoryx_posh/source/roudi/roudi.cpp index c88244a5cc..25d59eda2a 100644 --- a/iceoryx_posh/source/roudi/roudi.cpp +++ b/iceoryx_posh/source/roudi/roudi.cpp @@ -270,9 +270,15 @@ version::VersionInfo RouDi::parseRegisterMessage(const runtime::IpcMessage& mess uid_t& userId, int64_t& transmissionTimestamp) noexcept { - convert::from_string(message.getElementAtIndex(2).c_str(), pid); - convert::from_string(message.getElementAtIndex(3).c_str(), userId); - convert::from_string(message.getElementAtIndex(4).c_str(), transmissionTimestamp); + /// @todo iox-#2055 We need to introduce default value when failure occurs? + /// currently we use 0 for unsigned out parameters and -1 for signed out parameters + constexpr int64_t IOX_2055_WORKAROUND_SIGNED{-1}; + constexpr uint32_t IOX_2055_WORKAROUND_UNSIGNED{0}; + pid = convert::from_string(message.getElementAtIndex(2).c_str()).value_or(IOX_2055_WORKAROUND_UNSIGNED); + userId = + convert::from_string(message.getElementAtIndex(3).c_str()).value_or(IOX_2055_WORKAROUND_UNSIGNED); + transmissionTimestamp = + convert::from_string(message.getElementAtIndex(4).c_str()).value_or(IOX_2055_WORKAROUND_SIGNED); Serialization serializationVersionInfo(message.getElementAtIndex(5)); return serializationVersionInfo; } diff --git a/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp b/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp index 5645e839f8..118f0a47f1 100644 --- a/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp +++ b/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp @@ -100,12 +100,15 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm { uint16_t roudiId{0u}; constexpr uint64_t MAX_ROUDI_ID = ((1 << 16) - 1); - if (!convert::from_string(optarg, roudiId)) + auto result = convert::from_string(optarg); + if (!result.has_value()) { IOX_LOG(ERROR, "The RouDi id must be in the range of [0, " << MAX_ROUDI_ID << "]"); m_cmdLineArgs.run = false; + break; } + roudiId = result.value(); m_cmdLineArgs.uniqueRouDiId.emplace(roudiId); break; } @@ -168,32 +171,34 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm { uint32_t processTerminationDelayInSeconds{0u}; constexpr uint64_t MAX_PROCESS_TERMINATION_DELAY = std::numeric_limits::max(); - if (!convert::from_string(optarg, processTerminationDelayInSeconds)) + auto result = convert::from_string(optarg); + if (!result.has_value()) { IOX_LOG(ERROR, "The process termination delay must be in the range of [0, " << MAX_PROCESS_TERMINATION_DELAY << "]"); m_cmdLineArgs.run = false; + break; } - else - { - m_cmdLineArgs.processTerminationDelay = units::Duration::fromSeconds(processTerminationDelayInSeconds); - } + + processTerminationDelayInSeconds = result.value(); + m_cmdLineArgs.processTerminationDelay = units::Duration::fromSeconds(processTerminationDelayInSeconds); break; } case 'k': { uint32_t processKillDelayInSeconds{0u}; constexpr uint64_t MAX_PROCESS_KILL_DELAY = std::numeric_limits::max(); - if (!convert::from_string(optarg, processKillDelayInSeconds)) + auto result = convert::from_string(optarg); + if (!result.has_value()) { IOX_LOG(ERROR, "The process kill delay must be in the range of [0, " << MAX_PROCESS_KILL_DELAY << "]"); m_cmdLineArgs.run = false; + break; } - else - { - m_cmdLineArgs.processKillDelay = units::Duration::fromSeconds(processKillDelayInSeconds); - } + + processKillDelayInSeconds = result.value(); + m_cmdLineArgs.processKillDelay = units::Duration::fromSeconds(processKillDelayInSeconds); break; } case 'x': diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index c68e3ccc4f..c4fa38171f 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -29,7 +29,15 @@ namespace runtime IpcMessageType stringToIpcMessageType(const char* str) noexcept { std::underlying_type::type msg; - bool noError = convert::from_string(str, msg); + auto result = convert::from_string::type>(str); + bool noError{false}; + + if (result.has_value()) + { + noError = true; + msg = result.value(); + } + noError &= noError ? !(static_cast::type>(IpcMessageType::BEGIN) >= msg || static_cast::type>(IpcMessageType::END) <= msg) : false; @@ -44,7 +52,15 @@ std::string IpcMessageTypeToString(const IpcMessageType msg) noexcept IpcMessageErrorType stringToIpcMessageErrorType(const char* str) noexcept { std::underlying_type::type msg; - bool noError = (convert::from_string(str, msg)); + auto result = convert::from_string::type>(str); + bool noError{false}; + + if (result.has_value()) + { + noError = true; + msg = result.value(); + } + noError &= noError ? !(static_cast::type>(IpcMessageErrorType::BEGIN) >= msg || static_cast::type>(IpcMessageErrorType::END) <= msg) diff --git a/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp b/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp index 028dafd62b..c93bb34caa 100644 --- a/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp +++ b/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp @@ -235,19 +235,41 @@ IpcRuntimeInterface::RegAckResult IpcRuntimeInterface::waitForRegAck(int64_t tra } // read out the shared memory base address and save it - iox::convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), m_shmTopicSize); UntypedRelativePointer::offset_t segmentManagerOffset{UntypedRelativePointer::NULL_POINTER_OFFSET}; - iox::convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentManagerOffset); + UntypedRelativePointer::offset_t heartbeatOffset{UntypedRelativePointer::NULL_POINTER_OFFSET}; + int64_t receivedTimestamp{0U}; + + auto topic_size_result = + iox::convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); + auto segment_manager_offset_result = + iox::convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); + auto recv_timestamp_result = + iox::convert::from_string(receiveBuffer.getElementAtIndex(3U).c_str()); + auto segment_id_result = + iox::convert::from_string(receiveBuffer.getElementAtIndex(4U).c_str()); + auto heartbeat_offset_result = + iox::convert::from_string(receiveBuffer.getElementAtIndex(5U).c_str()); + + // validate conversion results + if (!topic_size_result.has_value() || !segment_manager_offset_result.has_value() + || !recv_timestamp_result.has_value() || !segment_id_result.has_value() + || !heartbeat_offset_result.has_value()) + { + return RegAckResult::CONVERSION_FAILURE; + } + + // assign conversion results + m_shmTopicSize = topic_size_result.value(); + m_segmentId = segment_id_result.value(); + segmentManagerOffset = segment_manager_offset_result.value(); + receivedTimestamp = recv_timestamp_result.value(); + heartbeatOffset = heartbeat_offset_result.value(); + m_segmentManagerAddressOffset.emplace(segmentManagerOffset); - int64_t receivedTimestamp{0U}; - iox::convert::from_string(receiveBuffer.getElementAtIndex(3U).c_str(), receivedTimestamp); - iox::convert::from_string(receiveBuffer.getElementAtIndex(4U).c_str(), m_segmentId); - UntypedRelativePointer::offset_t heartbeatOffset{UntypedRelativePointer::NULL_POINTER_OFFSET}; - iox::convert::from_string(receiveBuffer.getElementAtIndex(5U).c_str(), heartbeatOffset); /// @todo iox-#2055 this workaround is required sind the conversion of edge cases is broken - constexpr uint8_t IOX_2055_WORKAROUND{1}; - if (heartbeatOffset != (UntypedRelativePointer::NULL_POINTER_OFFSET - IOX_2055_WORKAROUND)) + /// I think it's solved. + if (heartbeatOffset != UntypedRelativePointer::NULL_POINTER_OFFSET) { m_heartbeatAddressOffset = heartbeatOffset; } diff --git a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp index e8a4e7dc51..dec429871f 100644 --- a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp +++ b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp @@ -185,12 +185,24 @@ PoshRuntimeImpl::requestPublisherFromRoudi(const IpcMessage& sendBuffer) noexcep std::string IpcMessage = receiveBuffer.getElementAtIndex(0U); if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_PUBLISHER_ACK) - { segment_id_underlying_t segmentId{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + auto segment_id_result = + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); + auto offset_result = + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); + + if (!segment_id_result.has_value() || !offset_result.has_value()) + { + IOX_LOG(ERROR, "conversion failed!"); + // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) + // here + return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + } + + segmentId = segment_id_result.value(); + offset = offset_result.value(); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } @@ -300,9 +312,22 @@ PoshRuntimeImpl::requestSubscriberFromRoudi(const IpcMessage& sendBuffer) noexce if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_SUBSCRIBER_ACK) { segment_id_underlying_t segmentId{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + auto segment_id_result = + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); + auto offset_result = + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); + + if (!segment_id_result.has_value() || !offset_result.has_value()) + { + IOX_LOG(ERROR, "conversion failed!"); + // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) + // here + return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + } + + segmentId = segment_id_result.value(); + offset = offset_result.value(); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } @@ -408,9 +433,22 @@ PoshRuntimeImpl::requestClientFromRoudi(const IpcMessage& sendBuffer) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_CLIENT_ACK) { segment_id_underlying_t segmentId{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + auto segment_id_result = + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); + auto offset_result = + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); + + if (!segment_id_result.has_value() || !offset_result.has_value()) + { + IOX_LOG(ERROR, "conversion failed!"); + // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) + // here + return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + } + + segmentId = segment_id_result.value(); + offset = offset_result.value(); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } @@ -516,9 +554,22 @@ PoshRuntimeImpl::requestServerFromRoudi(const IpcMessage& sendBuffer) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_SERVER_ACK) { segment_id_underlying_t segmentId{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + auto segment_id_result = + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); + auto offset_result = + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); + + if (!segment_id_result.has_value() || !offset_result.has_value()) + { + IOX_LOG(ERROR, "conversion failed!"); + // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) + // here + return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + } + + segmentId = segment_id_result.value(); + offset = offset_result.value(); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } @@ -560,9 +611,20 @@ popo::InterfacePortData* PoshRuntimeImpl::getMiddlewareInterface(const capro::In if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_INTERFACE_ACK) { segment_id_underlying_t segmentId{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + auto segment_id_result = + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); + auto offset_result = + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); + + if (!segment_id_result.has_value() || !offset_result.has_value()) + { + IOX_LOG(ERROR, "conversion failed!"); + return nullptr; + } + + segmentId = segment_id_result.value(); + offset = offset_result.value(); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return reinterpret_cast(ptr); } @@ -594,9 +656,20 @@ NodeData* PoshRuntimeImpl::createNode(const NodeProperty& nodeProperty) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_NODE_ACK) { segment_id_underlying_t segmentId{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + auto segment_id_result = + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); + auto offset_result = + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); + + if (!segment_id_result.has_value() || !offset_result.has_value()) + { + IOX_LOG(ERROR, "conversion failed!"); + return nullptr; + } + + segmentId = segment_id_result.value(); + offset = offset_result.value(); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return reinterpret_cast(ptr); } @@ -623,9 +696,22 @@ PoshRuntimeImpl::requestConditionVariableFromRoudi(const IpcMessage& sendBuffer) if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_CONDITION_VARIABLE_ACK) { segment_id_underlying_t segmentId{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str(), segmentId); UntypedRelativePointer::offset_t offset{0U}; - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str(), offset); + auto segment_id_result = + convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); + auto offset_result = + convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); + + if (!segment_id_result.has_value() || !offset_result.has_value()) + { + IOX_LOG(ERROR, "conversion failed!"); + // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) + // here + return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + } + + segmentId = segment_id_result.value(); + offset = offset_result.value(); auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); return ok(reinterpret_cast(ptr)); } diff --git a/tools/introspection/source/introspection_app.cpp b/tools/introspection/source/introspection_app.cpp index 4ceb70ca55..b861d304f8 100644 --- a/tools/introspection/source/introspection_app.cpp +++ b/tools/introspection/source/introspection_app.cpp @@ -102,15 +102,16 @@ void IntrospectionApp::parseCmdLineArguments(int argc, case 't': { uint64_t newUpdatePeriodMs; - if (convert::from_string(optarg, newUpdatePeriodMs)) - { - iox::units::Duration rate = iox::units::Duration::fromMilliseconds(newUpdatePeriodMs); - updatePeriodMs = bounded(rate, MIN_UPDATE_PERIOD, MAX_UPDATE_PERIOD); - } - else + auto result = convert::from_string(optarg); + if (!result.has_value()) { std::cout << "Invalid argument for 't'! Will be ignored!"; + break; } + + newUpdatePeriodMs = result.value(); + iox::units::Duration rate = iox::units::Duration::fromMilliseconds(newUpdatePeriodMs); + updatePeriodMs = bounded(rate, MIN_UPDATE_PERIOD, MAX_UPDATE_PERIOD); break; } From aaeb4a99aaa05002afa4c7bd7c48eb33ad843cc1 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 18:29:57 +0800 Subject: [PATCH 08/33] iox-#2055 Add comment for functions Signed-off-by: Dennis Liu --- .../design/include/iox/detail/posix_call.inl | 2 +- .../posix/design/include/iox/posix_call.hpp | 14 ++- .../utility/include/iox/detail/convert.hpp | 100 +++++++++++------- .../utility/include/iox/detail/convert.inl | 61 +---------- .../internal/runtime/ipc_interface_base.hpp | 1 + iceoryx_posh/source/roudi/process_manager.cpp | 3 +- 6 files changed, 74 insertions(+), 107 deletions(-) diff --git a/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl b/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl index 82c89b07fb..c93b780fff 100644 --- a/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl +++ b/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl @@ -147,7 +147,7 @@ inline PosixCallEvaluator PosixCallVerificator::returnVa } template -inline PosixCallEvaluator PosixCallVerificator::forceOkReturnValue() && noexcept +inline PosixCallEvaluator PosixCallVerificator::alwaysSuccess() && noexcept { m_details.hasSuccess = true; return PosixCallEvaluator(m_details); diff --git a/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp b/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp index 9edaff9205..5d196a5fee 100644 --- a/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp +++ b/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp @@ -132,11 +132,15 @@ class [[nodiscard]] PosixCallVerificator /// @return the PosixCallEvaluator which evaluates the errno values PosixCallEvaluator returnValueMatchesErrno() && noexcept; - /// @todo iox-#2055: from_string requires a method to return a never failed - /// (has_error() == false) PosixCallEvaluator. - /// @brief - /// @return - PosixCallEvaluator forceOkReturnValue() && noexcept; + /// @brief Sets the POSIX call to always be treated as successful. + /// @details This function marks the current POSIX call evaluation as always successful, + /// regardless of the actual outcome. It is particularly useful in scenarios + /// where the return value or error state should be ignored, and the operation + /// should always be considered successful. + /// @tparam ReturnType The return type of the POSIX call. + /// @return An instance of PosixCallEvaluator that represents the modified + /// state of the POSIX call evaluation, with success status enforced. + PosixCallEvaluator alwaysSuccess() && noexcept; private: template diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index b3f78c0d61..e529e8f968 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -92,83 +92,105 @@ class convert static iox::optional from_string(const char* v) noexcept; private: - /// @todo iox-#2055 - /// @brief - /// @tparam ValueType - /// @tparam CallType - /// @param call - /// @param errno_cache - /// @param end_ptr - /// @param v - /// @return + /// @brief Evaluates the return value from a POSIX call or similar function call. + /// This function checks if the call resulted in an error and validates the edge cases + /// of the conversion from string to a numeric value. It returns an optional containing + /// the converted value if successful, or nullopt if there's an error or edge case failure. + /// @tparam TargetType The type to which the string is being converted. + /// @tparam CallType The type of the call object. + /// @param call Reference to the call object. + /// @param errno_cache Cached errno value for error checking. + /// @param end_ptr Pointer to the character after the last character used in the conversion. + /// @param v Pointer to the input string. + /// @return Optional containing the converted value or nullopt. template static iox::optional evaluate_return_value(CallType& call, decltype(errno) errno_cache, const char* end_ptr, const char* v) noexcept; - /// @todo iox-#2055 - /// @brief Check the edge cases. If - /// @tparam Destination - /// @param errno_cache - /// @param end_ptr - /// @param v - /// @param check_value - /// @return + /// @brief Checks for edge cases in string conversion to a numeric type. + /// This function evaluates various conditions that might indicate an edge + /// case or an error in the conversion process from a string to a numeric type. + /// It checks for invalid input strings, conversion failures, errors indicated + /// by 'errno', and whether the converted value falls within the expected range. + /// @tparam TargetType The numeric type to which the string is being converted. + /// @tparam RequireCheckValType The type of the value being checked against edge cases. + /// @param errno_cache Cached value of 'errno' to check for conversion errors. + /// @param end_ptr Pointer to the character following the last character used + /// in the conversion, used to check for conversion failures. + /// @param v Pointer to the input string being converted. + /// @param require_check_val The value to be checked against edge cases. + /// @return True if no edge cases or errors are detected, false otherwise. template static bool check_edge_case(decltype(errno) errno_cache, const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept; - /// @todo iox-#2055 - /// @brief - /// @param v - /// @return + /// @brief Determines if a given string starts with a negative sign after skipping any leading spaces. + /// This function examines the input string and returns true if the first non-space character + /// is a negative sign ('-'). It is useful for parsing strings representing numeric values, + /// where the sign of the number needs to be determined. + /// @param v Pointer to the null-terminated input string to be checked. + /// @return True if the string starts with a negative sign after any leading spaces, false otherwise. + static bool start_with_neg_sign(const char* v) noexcept; - /// @todo iox-#2055 - /// @brief - /// @tparam RequireCheckValType - /// @param end_ptr - /// @param v - /// @param require_check_val - /// @return + /// @brief Checks if the string input is valid based on the results of its conversion. + /// This function determines the validity of the input string by analyzing the outcome + /// of a conversion function like strtoull. It checks whether the end_ptr overlaps with + /// the beginning of v, indicating no conversion occurred, or if the conversion did not + /// terminate at a null character '\0', both scenarios being indicative of an invalid input. + /// @tparam RequireCheckValType Type of the value being checked. + /// @param end_ptr Pointer to the character after the last character used in the conversion. + /// @param v Pointer to the input string. + /// @param require_check_val The value obtained from the conversion, used for comparison. + /// @return True if the input is valid for conversion, false otherwise. template static bool is_valid_input(const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept; - /// @todo iox-#2055 - /// @brief - /// @param errno_cache - /// @return + /// @brief Checks if the cached errno indicates a valid conversion. + /// This function assesses the errno value to determine if it represents + /// a common error scenario during string-to-numeric conversion. + /// @param errno_cache Cached errno value to be checked. + /// @return True if errno does not indicate an error, false otherwise. static bool is_valid_errno(decltype(errno) errno_cache) noexcept; - /// @todo iox-#2055 - /// @brief - /// @tparam TargetType - /// @tparam RequireCheckValType - /// @param require_check_val - /// @return + /// @brief Checks if the given value is within the allowable range for the target type. + /// This function evaluates whether the specified value falls within the numeric limits + /// of the target type, considering both upper and lower bounds. + /// @tparam TargetType The numeric type to be checked against. + /// @tparam RequireCheckValType Type of the value being checked. + /// @param require_check_val The value to be evaluated against the target type's range. + /// @return True if the value is within range, false otherwise. template static bool is_within_range(const RequireCheckValType& require_check_val) noexcept; - /// @todo iox-#2055 helper, I believe there's a more elegant way to implement this. + /// @todo iox-#2055 I believe there's a more elegant way to implement this. What do you think? private: + /// @brief Trait struct to determine if a type is an iox::string. + /// Provides a compile-time check to identify if a given type is an instance of iox::string. + /// @tparam T Type to be checked. template struct is_iox_string : std::false_type { }; + /// Specialization of is_iox_string for iox::string. template struct is_iox_string> : std::true_type { }; + /// @brief Helper struct to extract the capacity of an iox::string at compile time. + /// Provides a mechanism to obtain the capacity of an iox::string type. template struct GetCapacity; + /// Specialization of GetCapacity for iox::string. template struct GetCapacity> { diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 778ab462e3..49e48c6b07 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -164,7 +164,7 @@ inline iox::optional convert::from_string(const char* v) noe } auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) - .forceOkReturnValue() + .alwaysSuccess() .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -333,64 +333,6 @@ inline bool convert::start_with_neg_sign(const char* v) noexcept return (*v == '-'); } -// template -// inline bool convert::check_edge_case(decltype(errno) errno_cache, -// const char* end_ptr, -// const char* v, -// const RequireCheckValType& require_check_val) -// { -// // invalid string -// if (v == end_ptr && require_check_val == 0) -// { -// IOX_LOG(DEBUG, "invalid input"); -// return false; -// } - -// // end_ptr is not '\0' which means conversion failure at end_ptr -// if (end_ptr != nullptr && v != end_ptr && *end_ptr != '\0') -// { -// // can split and reconvert here? wait for implement later -// IOX_LOG(DEBUG, "conversion failed at " << end_ptr - v << " : " << *end_ptr); -// return false; -// } - -// // check errno -// if (errno_cache == ERANGE) -// { -// IOX_LOG(DEBUG, "ERANGE triggered during conversion"); -// return false; -// } - -// if (errno_cache == EINVAL) -// { -// IOX_LOG(DEBUG, "EINVAL triggered during conversion"); -// return false; -// } - -// if constexpr (std::is_arithmetic_v) -// { -// // out of range (upper bound) -// if (require_check_val > std::numeric_limits::max()) -// { -// IOX_LOG(DEBUG, -// require_check_val << " is out of range (upper bound), should be less than " -// << std::numeric_limits::max()); -// return false; -// } - -// // out of range (lower bound) -// if (require_check_val < std::numeric_limits::lowest()) -// { -// IOX_LOG(DEBUG, -// require_check_val << " is out of range (lower bound), should be larger than " -// << std::numeric_limits::lowest()); -// return false; -// } -// } - -// return true; -// } - template inline bool convert::check_edge_case(decltype(errno) errno_cache, const char* end_ptr, @@ -418,7 +360,6 @@ convert::evaluate_return_value(CallType& call, decltype(errno) errno_cache, cons return iox::optional(static_cast(call->value)); } - template inline bool convert::is_valid_input(const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept diff --git a/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_interface_base.hpp b/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_interface_base.hpp index 366703878a..9aa9b2dbf8 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_interface_base.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_interface_base.hpp @@ -120,6 +120,7 @@ enum class IpcMessageErrorType : int32_t CONDITION_VARIABLE_LIST_FULL, EVENT_VARIABLE_LIST_FULL, NODE_DATA_LIST_FULL, + SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE, END, }; diff --git a/iceoryx_posh/source/roudi/process_manager.cpp b/iceoryx_posh/source/roudi/process_manager.cpp index f1bb436c7c..3b7d121cd6 100644 --- a/iceoryx_posh/source/roudi/process_manager.cpp +++ b/iceoryx_posh/source/roudi/process_manager.cpp @@ -288,9 +288,8 @@ bool ProcessManager::addProcess(const RuntimeName_t& name, IOX_LOG(ERROR, "Could not register process '" << name << "' - too many processes"); return false; } + auto heartbeatPoolIndex = HeartbeatPool::Index::INVALID; - /// @todo iox-#2055 this workaround is required sind the conversion of edge cases is broken - /// I think it's solved. iox::UntypedRelativePointer::offset_t heartbeatOffset{iox::UntypedRelativePointer::NULL_POINTER_OFFSET}; if (isMonitored) From 1347500ba5d407d73b01f8a7c7c6d82094ac9fbb Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 18:30:44 +0800 Subject: [PATCH 09/33] iox-#2055 Add a new IpcMessageErrorType In iceoryx_posh/source/runtime/posh_runtime_impl.cpp, convert::from_string are used to convert the segment id and offset. However, the conversion failure might occur. Therefore, an new error type: `SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE` are introduced to be utilized as an error return value, reminding user a conversion failure happened in posh runtime. Signed-off-by: Dennis Liu --- .../source/runtime/ipc_runtime_interface.cpp | 2 -- .../source/runtime/posh_runtime_impl.cpp | 30 +++++++------------ 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp b/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp index c93bb34caa..edb1f9342c 100644 --- a/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp +++ b/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp @@ -267,8 +267,6 @@ IpcRuntimeInterface::RegAckResult IpcRuntimeInterface::waitForRegAck(int64_t tra m_segmentManagerAddressOffset.emplace(segmentManagerOffset); - /// @todo iox-#2055 this workaround is required sind the conversion of edge cases is broken - /// I think it's solved. if (heartbeatOffset != UntypedRelativePointer::NULL_POINTER_OFFSET) { m_heartbeatAddressOffset = heartbeatOffset; diff --git a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp index dec429871f..d722f7060e 100644 --- a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp +++ b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp @@ -195,10 +195,8 @@ PoshRuntimeImpl::requestPublisherFromRoudi(const IpcMessage& sendBuffer) noexcep if (!segment_id_result.has_value() || !offset_result.has_value()) { - IOX_LOG(ERROR, "conversion failed!"); - // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) - // here - return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); + return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); } segmentId = segment_id_result.value(); @@ -320,10 +318,8 @@ PoshRuntimeImpl::requestSubscriberFromRoudi(const IpcMessage& sendBuffer) noexce if (!segment_id_result.has_value() || !offset_result.has_value()) { - IOX_LOG(ERROR, "conversion failed!"); - // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) - // here - return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); + return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); } segmentId = segment_id_result.value(); @@ -441,10 +437,8 @@ PoshRuntimeImpl::requestClientFromRoudi(const IpcMessage& sendBuffer) noexcept if (!segment_id_result.has_value() || !offset_result.has_value()) { - IOX_LOG(ERROR, "conversion failed!"); - // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) - // here - return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); + return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); } segmentId = segment_id_result.value(); @@ -562,10 +556,8 @@ PoshRuntimeImpl::requestServerFromRoudi(const IpcMessage& sendBuffer) noexcept if (!segment_id_result.has_value() || !offset_result.has_value()) { - IOX_LOG(ERROR, "conversion failed!"); - // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) - // here - return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); + return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); } segmentId = segment_id_result.value(); @@ -704,10 +696,8 @@ PoshRuntimeImpl::requestConditionVariableFromRoudi(const IpcMessage& sendBuffer) if (!segment_id_result.has_value() || !offset_result.has_value()) { - IOX_LOG(ERROR, "conversion failed!"); - // @todo iox-#2055 should return an IpcMessageError (maybe create a new error tpye: INVALID_CONVERSION) - // here - return err(IpcMessageErrorType::REQUEST_PUBLISHER_INVALID_RESPONSE); + IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); + return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); } segmentId = segment_id_result.value(); From c171c7ff45096a0dccf4734dc9f60119ac1aad18 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 19:17:12 +0800 Subject: [PATCH 10/33] iox-#2055 Try to fix macos sanitizer problem Signed-off-by: Dennis Liu --- iceoryx_hoofs/utility/include/iox/detail/convert.inl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 49e48c6b07..227b032780 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -178,10 +178,10 @@ template <> inline iox::optional convert::from_string(const char* v, unsigned long& dest) noexcept { uint64_t temp{0}; - auto ret = from_string(v, temp); + auto ret = from_string(v); if (!ret.has_value()) { - return iox::optional{}; + return iox::nullopt; } return iox::optional{static_cast(ret.value())}; } @@ -193,11 +193,11 @@ inline iox::optional convert::from_string(const ch template <> inline iox::optional convert::from_string(const char* v, uintptr_t& dest) noexcept { - uint64_t temp{0}; - auto ret = from_string(v, temp); + uint32_t temp{0}; + auto ret = from_string(v); if (!ret.has_value()) { - return iox::optional{}; + return iox::nullopt; } return iox::optional{static_cast(ret.value())}; } From 31cdc6491a6b32f9f1edb6bc3ef20f67fd336436 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 21:01:00 +0800 Subject: [PATCH 11/33] iox-#2055 Try to fix uninitialize error Signed-off-by: Dennis Liu --- iceoryx_posh/source/popo/client_options.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iceoryx_posh/source/popo/client_options.cpp b/iceoryx_posh/source/popo/client_options.cpp index 5f7aef3d2f..07a2480f72 100644 --- a/iceoryx_posh/source/popo/client_options.cpp +++ b/iceoryx_posh/source/popo/client_options.cpp @@ -35,9 +35,9 @@ expected ClientOptions::deserialize(const S using QueueFullPolicyUT = std::underlying_type_t; using ConsumerTooSlowPolicyUT = std::underlying_type_t; - ClientOptions clientOptions; - QueueFullPolicyUT responseQueueFullPolicy; - ConsumerTooSlowPolicyUT serverTooSlowPolicy; + ClientOptions clientOptions{}; + QueueFullPolicyUT responseQueueFullPolicy{}; + ConsumerTooSlowPolicyUT serverTooSlowPolicy{}; auto deserializationSuccessful = serialized.extract(clientOptions.responseQueueCapacity, clientOptions.nodeName, From 0a3eb9f96abc205e6de5258d24f88e9597276981 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 21:56:45 +0800 Subject: [PATCH 12/33] iox-#2055 Fix MacOS and arm-none-eabi-gcc API Signed-off-by: Dennis Liu --- iceoryx_hoofs/utility/include/iox/detail/convert.inl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 227b032780..3751d86470 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -175,7 +175,7 @@ inline iox::optional convert::from_string(const char* v) noe /// introduced for mac os since unsigned long is not uint64_t despite it has the same size /// who knows why ¯\_(ツ)_/¯ template <> -inline iox::optional convert::from_string(const char* v, unsigned long& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { uint64_t temp{0}; auto ret = from_string(v); @@ -191,7 +191,7 @@ inline iox::optional convert::from_string(const ch /// introduced for 32-bit arm-none-eabi-gcc since uintptr_t is not uint32_t despite it has the same size /// who knows why ¯\_(ツ)_/¯ template <> -inline iox::optional convert::from_string(const char* v, uintptr_t& dest) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { uint32_t temp{0}; auto ret = from_string(v); From 734ac260a01b54f65f61cc737a9a7d0750920c4e Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 22:13:55 +0800 Subject: [PATCH 13/33] iox-#2055 Initialize variables Signed-off-by: Dennis Liu --- iceoryx_posh/source/popo/server_options.cpp | 6 +++--- iceoryx_posh/source/popo/subscriber_options.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iceoryx_posh/source/popo/server_options.cpp b/iceoryx_posh/source/popo/server_options.cpp index bbee064328..9042bb60c1 100644 --- a/iceoryx_posh/source/popo/server_options.cpp +++ b/iceoryx_posh/source/popo/server_options.cpp @@ -35,9 +35,9 @@ expected ServerOptions::deserialize(const S using QueueFullPolicyUT = std::underlying_type_t; using ClientTooSlowPolicyUT = std::underlying_type_t; - ServerOptions serverOptions; - QueueFullPolicyUT requestQueueFullPolicy; - ClientTooSlowPolicyUT clientTooSlowPolicy; + ServerOptions serverOptions{}; + QueueFullPolicyUT requestQueueFullPolicy{}; + ClientTooSlowPolicyUT clientTooSlowPolicy{}; auto deserializationSuccessful = serialized.extract(serverOptions.requestQueueCapacity, serverOptions.nodeName, diff --git a/iceoryx_posh/source/popo/subscriber_options.cpp b/iceoryx_posh/source/popo/subscriber_options.cpp index 177343f769..b87aaee094 100644 --- a/iceoryx_posh/source/popo/subscriber_options.cpp +++ b/iceoryx_posh/source/popo/subscriber_options.cpp @@ -36,8 +36,8 @@ SubscriberOptions::deserialize(const Serialization& serialized) noexcept { using QueueFullPolicyUT = std::underlying_type_t; - SubscriberOptions subscriberOptions; - QueueFullPolicyUT queueFullPolicy; + SubscriberOptions subscriberOptions{}; + QueueFullPolicyUT queueFullPolicy{}; auto deserializationSuccessful = serialized.extract(subscriberOptions.queueCapacity, subscriberOptions.historyRequest, From c486577872733147de0b682418bea376330166c9 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 14 Dec 2023 23:39:20 +0800 Subject: [PATCH 14/33] iox-#2055 Remove unsed variables Signed-off-by: Dennis Liu --- iceoryx_hoofs/utility/include/iox/detail/convert.inl | 2 -- 1 file changed, 2 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 3751d86470..4c7f58cacf 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -177,7 +177,6 @@ inline iox::optional convert::from_string(const char* v) noe template <> inline iox::optional convert::from_string(const char* v) noexcept { - uint64_t temp{0}; auto ret = from_string(v); if (!ret.has_value()) { @@ -193,7 +192,6 @@ inline iox::optional convert::from_string(const ch template <> inline iox::optional convert::from_string(const char* v) noexcept { - uint32_t temp{0}; auto ret = from_string(v); if (!ret.has_value()) { From 809dddca229ad98fa46ad08ccfd271927ae83cab Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Tue, 19 Dec 2023 16:24:18 +0800 Subject: [PATCH 15/33] iox-#2055 Refactor the usage of from_string - 1 Signed-off-by: Dennis Liu --- iceoryx_examples/iceperf/main_follower.cpp | 3 +- .../cli/include/iox/cli/arguments.inl | 8 +-- .../include/iox/detail/serialization.inl | 14 +---- .../runtime/ipc_runtime_interface.hpp | 2 +- iceoryx_posh/source/roudi/port_manager.cpp | 3 +- iceoryx_posh/source/roudi/roudi.cpp | 18 +++--- .../source/roudi/roudi_cmd_line_parser.cpp | 9 +-- .../source/runtime/ipc_interface_base.cpp | 58 +++++++++++++------ .../source/runtime/ipc_runtime_interface.cpp | 2 +- .../source/introspection_app.cpp | 3 +- 10 files changed, 62 insertions(+), 58 deletions(-) diff --git a/iceoryx_examples/iceperf/main_follower.cpp b/iceoryx_examples/iceperf/main_follower.cpp index 04e055e6b1..23805661b6 100644 --- a/iceoryx_examples/iceperf/main_follower.cpp +++ b/iceoryx_examples/iceperf/main_follower.cpp @@ -47,7 +47,6 @@ int main(int argc, char* argv[]) { constexpr decltype(EXIT_SUCCESS) MOO{EXIT_SUCCESS}; - uint64_t intensity{0U}; auto result = iox::convert::from_string(optarg); if (!result.has_value()) { @@ -55,7 +54,7 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } - intensity = result.value(); + const auto intensity = result.value(); if (intensity > 100) { diff --git a/iceoryx_hoofs/cli/include/iox/cli/arguments.inl b/iceoryx_hoofs/cli/include/iox/cli/arguments.inl index 26105ee48f..cad915563c 100644 --- a/iceoryx_hoofs/cli/include/iox/cli/arguments.inl +++ b/iceoryx_hoofs/cli/include/iox/cli/arguments.inl @@ -26,15 +26,13 @@ namespace cli template inline expected Arguments::convertFromString(const Argument_t& stringValue) const noexcept { - // @todo iox-#2055 there are edge cases which lead to not initializing the value even when the return value of - // 'fromString' is true; value initialization can be removed when #2055 is fixed - T value{}; - if (!convert::fromString(stringValue.c_str(), value)) + auto result = convert::from_string(stringValue.c_str()); + if (!result.has_value()) { std::cout << "\"" << stringValue.c_str() << "\" could not be converted to the requested type" << std::endl; return err(Error::UNABLE_TO_CONVERT_VALUE); } - return ok(value); + return ok(result.value()); } template <> diff --git a/iceoryx_hoofs/utility/include/iox/detail/serialization.inl b/iceoryx_hoofs/utility/include/iox/detail/serialization.inl index 61eecb40d7..7c8ee96c55 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/serialization.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/serialization.inl @@ -113,7 +113,6 @@ inline bool Serialization::removeFirstEntry(std::string& firstEntry, std::string return false; } - uint64_t length{0}; auto result = convert::from_string(remainder.substr(0, pos).c_str()); if (!result.has_value()) @@ -121,7 +120,7 @@ inline bool Serialization::removeFirstEntry(std::string& firstEntry, std::string return false; } - length = result.value(); + const auto length = result.value(); if (remainder.size() < pos + length + 1U) { @@ -146,16 +145,7 @@ inline bool Serialization::getNth(const unsigned int index, T& t) const noexcept return false; } } - - auto result = convert::from_string(entry.c_str()); - - if (!result.has_value()) - { - return false; - } - - t = result.value(); - return true; + return convert::from_string(entry.c_str()).and_then([&t](const auto& value) { t = value; }).has_value(); } } // namespace iox diff --git a/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_runtime_interface.hpp b/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_runtime_interface.hpp index 79a4f356af..cc9b98760b 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_runtime_interface.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_runtime_interface.hpp @@ -71,7 +71,7 @@ class IpcRuntimeInterface { SUCCESS, TIMEOUT, - CONVERSION_FAILURE + MALFORMED_RESPONSE }; void waitForRoudi(deadline_timer& timer) noexcept; diff --git a/iceoryx_posh/source/roudi/port_manager.cpp b/iceoryx_posh/source/roudi/port_manager.cpp index 389834ac8f..f2751be78e 100644 --- a/iceoryx_posh/source/roudi/port_manager.cpp +++ b/iceoryx_posh/source/roudi/port_manager.cpp @@ -31,7 +31,6 @@ namespace roudi { capro::Interfaces StringToCaProInterface(const capro::IdString_t& str) noexcept { - int32_t i{0}; auto result = convert::from_string(str.c_str()); if (!result.has_value()) { @@ -39,7 +38,7 @@ capro::Interfaces StringToCaProInterface(const capro::IdString_t& str) noexcept return capro::Interfaces::INTERNAL; } - i = result.has_value(); + const auto i = result.value(); if (i >= static_cast(capro::Interfaces::INTERFACE_END)) { diff --git a/iceoryx_posh/source/roudi/roudi.cpp b/iceoryx_posh/source/roudi/roudi.cpp index 25d59eda2a..c2e562db86 100644 --- a/iceoryx_posh/source/roudi/roudi.cpp +++ b/iceoryx_posh/source/roudi/roudi.cpp @@ -270,15 +270,15 @@ version::VersionInfo RouDi::parseRegisterMessage(const runtime::IpcMessage& mess uid_t& userId, int64_t& transmissionTimestamp) noexcept { - /// @todo iox-#2055 We need to introduce default value when failure occurs? - /// currently we use 0 for unsigned out parameters and -1 for signed out parameters - constexpr int64_t IOX_2055_WORKAROUND_SIGNED{-1}; - constexpr uint32_t IOX_2055_WORKAROUND_UNSIGNED{0}; - pid = convert::from_string(message.getElementAtIndex(2).c_str()).value_or(IOX_2055_WORKAROUND_UNSIGNED); - userId = - convert::from_string(message.getElementAtIndex(3).c_str()).value_or(IOX_2055_WORKAROUND_UNSIGNED); - transmissionTimestamp = - convert::from_string(message.getElementAtIndex(4).c_str()).value_or(IOX_2055_WORKAROUND_SIGNED); + convert::from_string(message.getElementAtIndex(2).c_str()).and_then([&pid](const auto value) { + pid = value; + }); + convert::from_string(message.getElementAtIndex(3).c_str()).and_then([&userId](const auto value) { + userId = value; + }); + convert::from_string(message.getElementAtIndex(4).c_str()) + .and_then([&transmissionTimestamp](const auto value) { transmissionTimestamp = value; }); + Serialization serializationVersionInfo(message.getElementAtIndex(5)); return serializationVersionInfo; } diff --git a/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp b/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp index 118f0a47f1..ff2164e21c 100644 --- a/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp +++ b/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp @@ -98,7 +98,6 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm break; case 'u': { - uint16_t roudiId{0u}; constexpr uint64_t MAX_ROUDI_ID = ((1 << 16) - 1); auto result = convert::from_string(optarg); if (!result.has_value()) @@ -108,7 +107,7 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm break; } - roudiId = result.value(); + auto roudiId = result.value(); m_cmdLineArgs.uniqueRouDiId.emplace(roudiId); break; } @@ -169,7 +168,6 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm } case 't': { - uint32_t processTerminationDelayInSeconds{0u}; constexpr uint64_t MAX_PROCESS_TERMINATION_DELAY = std::numeric_limits::max(); auto result = convert::from_string(optarg); if (!result.has_value()) @@ -181,13 +179,12 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm break; } - processTerminationDelayInSeconds = result.value(); + const auto processTerminationDelayInSeconds = result.value(); m_cmdLineArgs.processTerminationDelay = units::Duration::fromSeconds(processTerminationDelayInSeconds); break; } case 'k': { - uint32_t processKillDelayInSeconds{0u}; constexpr uint64_t MAX_PROCESS_KILL_DELAY = std::numeric_limits::max(); auto result = convert::from_string(optarg); if (!result.has_value()) @@ -197,7 +194,7 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm break; } - processKillDelayInSeconds = result.value(); + const auto processKillDelayInSeconds = result.value(); m_cmdLineArgs.processKillDelay = units::Duration::fromSeconds(processKillDelayInSeconds); break; } diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index c4fa38171f..107cccb511 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -30,18 +30,32 @@ IpcMessageType stringToIpcMessageType(const char* str) noexcept { std::underlying_type::type msg; auto result = convert::from_string::type>(str); - bool noError{false}; - if (result.has_value()) + if (!result.has_value()) { - noError = true; - msg = result.value(); + return IpcMessageType::NOTYPE; } - noError &= noError ? !(static_cast::type>(IpcMessageType::BEGIN) >= msg - || static_cast::type>(IpcMessageType::END) <= msg) - : false; - return noError ? (static_cast(msg)) : IpcMessageType::NOTYPE; + msg = result.value(); + + if (static_cast::type>(IpcMessageType::BEGIN) >= msg + || static_cast::type>(IpcMessageType::END) <= msg) + { + return IpcMessageType::NOTYPE; + } + + return static_cast(msg); + + // // XXX We would like to write code in the following way but failed + // // The return type of result.and_then seems have to be the same with input type + // return result.and_then([](const auto& msg) { + // if (static_cast::type>(IpcMessageType::BEGIN) >= msg + // || static_cast::type>(IpcMessageType::END) <= msg) { + // return iox::optional{}; + // } + // return iox::optional{static_cast(msg)}; + // }) + // .value_or(IpcMessageType::NOTYPE); } std::string IpcMessageTypeToString(const IpcMessageType msg) noexcept @@ -52,20 +66,28 @@ std::string IpcMessageTypeToString(const IpcMessageType msg) noexcept IpcMessageErrorType stringToIpcMessageErrorType(const char* str) noexcept { std::underlying_type::type msg; - auto result = convert::from_string::type>(str); - bool noError{false}; + auto result = convert::from_string::type>(str); + + msg = result.value(); - if (result.has_value()) + if (static_cast::type>(IpcMessageErrorType::BEGIN) >= msg + || static_cast::type>(IpcMessageErrorType::END) <= msg) { - noError = true; - msg = result.value(); + return IpcMessageErrorType::NOTYPE; } - noError &= noError - ? !(static_cast::type>(IpcMessageErrorType::BEGIN) >= msg - || static_cast::type>(IpcMessageErrorType::END) <= msg) - : false; - return noError ? (static_cast(msg)) : IpcMessageErrorType::NOTYPE; + return static_cast(msg); + + // // XXX We would like to write code in the following way but failed + // // The return type of result.and_then seems have to be the same with input type + // return result.and_then([](const auto& msg) { + // if (static_cast::type>(IpcMessageErrorType::BEGIN) >= msg + // || static_cast::type>(IpcMessageErrorType::END) <= msg) { + // return iox::optional{}; + // } + // return iox::optional{static_cast(msg)}; + // }) + // .value_or(IpcMessageType::NOTYPE); } std::string IpcMessageErrorTypeToString(const IpcMessageErrorType msg) noexcept diff --git a/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp b/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp index edb1f9342c..df36b89f6c 100644 --- a/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp +++ b/iceoryx_posh/source/runtime/ipc_runtime_interface.cpp @@ -255,7 +255,7 @@ IpcRuntimeInterface::RegAckResult IpcRuntimeInterface::waitForRegAck(int64_t tra || !recv_timestamp_result.has_value() || !segment_id_result.has_value() || !heartbeat_offset_result.has_value()) { - return RegAckResult::CONVERSION_FAILURE; + return RegAckResult::MALFORMED_RESPONSE; } // assign conversion results diff --git a/tools/introspection/source/introspection_app.cpp b/tools/introspection/source/introspection_app.cpp index b861d304f8..4622009f99 100644 --- a/tools/introspection/source/introspection_app.cpp +++ b/tools/introspection/source/introspection_app.cpp @@ -101,7 +101,6 @@ void IntrospectionApp::parseCmdLineArguments(int argc, case 't': { - uint64_t newUpdatePeriodMs; auto result = convert::from_string(optarg); if (!result.has_value()) { @@ -109,7 +108,7 @@ void IntrospectionApp::parseCmdLineArguments(int argc, break; } - newUpdatePeriodMs = result.value(); + const auto newUpdatePeriodMs = result.value(); iox::units::Duration rate = iox::units::Duration::fromMilliseconds(newUpdatePeriodMs); updatePeriodMs = bounded(rate, MIN_UPDATE_PERIOD, MAX_UPDATE_PERIOD); break; From c9ffbf2e079e5bb5aac1b5dc55dd19aa90dcfce8 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Wed, 20 Dec 2023 22:40:08 +0800 Subject: [PATCH 16/33] iox-#2055 Change the `from_string` template arg Change the template args of specialization of `from_string` from length fixed type to basic type. Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.inl | 62 +++++-------------- 1 file changed, 16 insertions(+), 46 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 4c7f58cacf..9e959481a7 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -153,7 +153,7 @@ inline iox::optional convert::from_string(const char* } template <> -inline iox::optional convert::from_string(const char* v) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { errno = 0; char* end_ptr = nullptr; @@ -168,41 +168,11 @@ inline iox::optional convert::from_string(const char* v) noe .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } -#ifdef __APPLE__ -/// introduced for mac os since unsigned long is not uint64_t despite it has the same size -/// who knows why ¯\_(ツ)_/¯ template <> -inline iox::optional convert::from_string(const char* v) noexcept -{ - auto ret = from_string(v); - if (!ret.has_value()) - { - return iox::nullopt; - } - return iox::optional{static_cast(ret.value())}; -} -#endif - -#if defined(__GNUC__) && (INTPTR_MAX == INT32_MAX) -/// introduced for 32-bit arm-none-eabi-gcc since uintptr_t is not uint32_t despite it has the same size -/// who knows why ¯\_(ツ)_/¯ -template <> -inline iox::optional convert::from_string(const char* v) noexcept -{ - auto ret = from_string(v); - if (!ret.has_value()) - { - return iox::nullopt; - } - return iox::optional{static_cast(ret.value())}; -} -#endif - -template <> -inline iox::optional convert::from_string(const char* v) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { errno = 0; char* end_ptr = nullptr; @@ -217,11 +187,11 @@ inline iox::optional convert::from_string(const char* v) noe .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> -inline iox::optional convert::from_string(const char* v) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { errno = 0; char* end_ptr = nullptr; @@ -236,11 +206,11 @@ inline iox::optional convert::from_string(const char* v) noe .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> -inline iox::optional convert::from_string(const char* v) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { errno = 0; char* end_ptr = nullptr; @@ -255,11 +225,11 @@ inline iox::optional convert::from_string(const char* v) noexc .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> -inline iox::optional convert::from_string(const char* v) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { errno = 0; char* end_ptr = nullptr; @@ -269,11 +239,11 @@ inline iox::optional convert::from_string(const char* v) noexc .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> -inline iox::optional convert::from_string(const char* v) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { errno = 0; char* end_ptr = nullptr; @@ -283,11 +253,11 @@ inline iox::optional convert::from_string(const char* v) noexc .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> -inline iox::optional convert::from_string(const char* v) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { errno = 0; char* end_ptr = nullptr; @@ -297,11 +267,11 @@ inline iox::optional convert::from_string(const char* v) noexc .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } template <> -inline iox::optional convert::from_string(const char* v) noexcept +inline iox::optional convert::from_string(const char* v) noexcept { errno = 0; char* end_ptr = nullptr; @@ -311,7 +281,7 @@ inline iox::optional convert::from_string(const char* v) noexcep .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, errno, end_ptr, v); } inline bool convert::start_with_neg_sign(const char* v) noexcept From ee6121e04993f6b1f5a6ed8a043d4f59584d3b77 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Wed, 20 Dec 2023 23:10:07 +0800 Subject: [PATCH 17/33] iox-#2055 Refactor roudi_cmd_line_parser.cpp Signed-off-by: Dennis Liu --- .../source/roudi/roudi_cmd_line_parser.cpp | 56 ++++++++----------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp b/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp index ff2164e21c..efb3fdaf71 100644 --- a/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp +++ b/iceoryx_posh/source/roudi/roudi_cmd_line_parser.cpp @@ -99,16 +99,12 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm case 'u': { constexpr uint64_t MAX_ROUDI_ID = ((1 << 16) - 1); - auto result = convert::from_string(optarg); - if (!result.has_value()) - { - IOX_LOG(ERROR, "The RouDi id must be in the range of [0, " << MAX_ROUDI_ID << "]"); - m_cmdLineArgs.run = false; - break; - } - - auto roudiId = result.value(); - m_cmdLineArgs.uniqueRouDiId.emplace(roudiId); + convert::from_string(optarg) + .and_then([&](const auto result) { m_cmdLineArgs.uniqueRouDiId.emplace(result); }) + .or_else([&] { + IOX_LOG(ERROR, "The RouDi id must be in the range of [0, " << MAX_ROUDI_ID << "]"); + m_cmdLineArgs.run = false; + }); break; } case 'm': @@ -169,33 +165,29 @@ CmdLineParser::parse(int argc, char* argv[], const CmdLineArgumentParsingMode cm case 't': { constexpr uint64_t MAX_PROCESS_TERMINATION_DELAY = std::numeric_limits::max(); - auto result = convert::from_string(optarg); - if (!result.has_value()) - { - IOX_LOG(ERROR, - "The process termination delay must be in the range of [0, " << MAX_PROCESS_TERMINATION_DELAY - << "]"); - m_cmdLineArgs.run = false; - break; - } - - const auto processTerminationDelayInSeconds = result.value(); - m_cmdLineArgs.processTerminationDelay = units::Duration::fromSeconds(processTerminationDelayInSeconds); + convert::from_string(optarg) + .and_then([&](const auto result) { + m_cmdLineArgs.processTerminationDelay = units::Duration::fromSeconds(result); + }) + .or_else([&] { + IOX_LOG(ERROR, + "The process termination delay must be in the range of [0, " + << MAX_PROCESS_TERMINATION_DELAY << "]"); + m_cmdLineArgs.run = false; + }); break; } case 'k': { constexpr uint64_t MAX_PROCESS_KILL_DELAY = std::numeric_limits::max(); - auto result = convert::from_string(optarg); - if (!result.has_value()) - { - IOX_LOG(ERROR, "The process kill delay must be in the range of [0, " << MAX_PROCESS_KILL_DELAY << "]"); - m_cmdLineArgs.run = false; - break; - } - - const auto processKillDelayInSeconds = result.value(); - m_cmdLineArgs.processKillDelay = units::Duration::fromSeconds(processKillDelayInSeconds); + convert::from_string(optarg) + .and_then( + [&](const auto result) { m_cmdLineArgs.processKillDelay = units::Duration::fromSeconds(result); }) + .or_else([&] { + IOX_LOG(ERROR, + "The process kill delay must be in the range of [0, " << MAX_PROCESS_KILL_DELAY << "]"); + m_cmdLineArgs.run = false; + }); break; } case 'x': From dd422c220f13fcf4f0c445068738938b8a4be6c9 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 01:38:40 +0800 Subject: [PATCH 18/33] iox-#2055 Refactor id and offset conversion Function named `convert_id_and_offset` was created. Signed-off-by: Dennis Liu --- .../internal/runtime/ipc_interface_base.hpp | 3 +- .../internal/runtime/posh_runtime_impl.hpp | 3 + .../source/runtime/ipc_interface_base.cpp | 5 +- .../source/runtime/posh_runtime_impl.cpp | 158 ++++++++---------- 4 files changed, 77 insertions(+), 92 deletions(-) diff --git a/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_interface_base.hpp b/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_interface_base.hpp index 9aa9b2dbf8..cd6c83b1ed 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_interface_base.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/runtime/ipc_interface_base.hpp @@ -120,7 +120,8 @@ enum class IpcMessageErrorType : int32_t CONDITION_VARIABLE_LIST_FULL, EVENT_VARIABLE_LIST_FULL, NODE_DATA_LIST_FULL, - SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE, + SEGMENT_ID_CONVERSION_FAILURE, + OFFSET_CONVERSION_FAILURE, END, }; diff --git a/iceoryx_posh/include/iceoryx_posh/internal/runtime/posh_runtime_impl.hpp b/iceoryx_posh/include/iceoryx_posh/internal/runtime/posh_runtime_impl.hpp index 55f2606172..ab3fc6d228 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/runtime/posh_runtime_impl.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/runtime/posh_runtime_impl.hpp @@ -106,6 +106,9 @@ class PoshRuntimeImpl : public PoshRuntime expected requestConditionVariableFromRoudi(const IpcMessage& sendBuffer) noexcept; + expected, IpcMessageErrorType> + convert_id_and_offset(IpcMessage& msg); + mutable optional m_appIpcRequestMutex; IpcRuntimeInterface m_ipcChannelInterface; diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index 107cccb511..158164bcee 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -28,8 +28,9 @@ namespace runtime { IpcMessageType stringToIpcMessageType(const char* str) noexcept { - std::underlying_type::type msg; - auto result = convert::from_string::type>(str); + using UnderlyingType = std::underlying_type::type; + UnderlyingType msg; + auto result = convert::from_string(str); if (!result.has_value()) { diff --git a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp index d722f7060e..5e72e4a0e6 100644 --- a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp +++ b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp @@ -186,22 +186,16 @@ PoshRuntimeImpl::requestPublisherFromRoudi(const IpcMessage& sendBuffer) noexcep if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_PUBLISHER_ACK) { - segment_id_underlying_t segmentId{0U}; - UntypedRelativePointer::offset_t offset{0U}; - auto segment_id_result = - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); - auto offset_result = - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); - - if (!segment_id_result.has_value() || !offset_result.has_value()) + auto result = convert_id_and_offset(receiveBuffer); + + if (!result) { - IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); - return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); + return err(result.error()); } - segmentId = segment_id_result.value(); - offset = offset_result.value(); - auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); + auto [segment_id, offset] = result.value(); + + auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segment_id}, offset); return ok(reinterpret_cast(ptr)); } } @@ -309,22 +303,16 @@ PoshRuntimeImpl::requestSubscriberFromRoudi(const IpcMessage& sendBuffer) noexce if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_SUBSCRIBER_ACK) { - segment_id_underlying_t segmentId{0U}; - UntypedRelativePointer::offset_t offset{0U}; - auto segment_id_result = - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); - auto offset_result = - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); - - if (!segment_id_result.has_value() || !offset_result.has_value()) + auto result = convert_id_and_offset(receiveBuffer); + + if (!result) { - IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); - return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); + return err(result.error()); } - segmentId = segment_id_result.value(); - offset = offset_result.value(); - auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); + auto [segment_id, offset] = result.value(); + + auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segment_id}, offset); return ok(reinterpret_cast(ptr)); } } @@ -428,22 +416,16 @@ PoshRuntimeImpl::requestClientFromRoudi(const IpcMessage& sendBuffer) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_CLIENT_ACK) { - segment_id_underlying_t segmentId{0U}; - UntypedRelativePointer::offset_t offset{0U}; - auto segment_id_result = - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); - auto offset_result = - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); - - if (!segment_id_result.has_value() || !offset_result.has_value()) + auto result = convert_id_and_offset(receiveBuffer); + + if (!result) { - IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); - return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); + return err(result.error()); } - segmentId = segment_id_result.value(); - offset = offset_result.value(); - auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); + auto [segment_id, offset] = result.value(); + + auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segment_id}, offset); return ok(reinterpret_cast(ptr)); } } @@ -547,22 +529,16 @@ PoshRuntimeImpl::requestServerFromRoudi(const IpcMessage& sendBuffer) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_SERVER_ACK) { - segment_id_underlying_t segmentId{0U}; - UntypedRelativePointer::offset_t offset{0U}; - auto segment_id_result = - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); - auto offset_result = - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); - - if (!segment_id_result.has_value() || !offset_result.has_value()) + auto result = convert_id_and_offset(receiveBuffer); + + if (!result) { - IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); - return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); + return err(result.error()); } - segmentId = segment_id_result.value(); - offset = offset_result.value(); - auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); + auto [segment_id, offset] = result.value(); + + auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segment_id}, offset); return ok(reinterpret_cast(ptr)); } } @@ -602,22 +578,16 @@ popo::InterfacePortData* PoshRuntimeImpl::getMiddlewareInterface(const capro::In if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_INTERFACE_ACK) { - segment_id_underlying_t segmentId{0U}; - UntypedRelativePointer::offset_t offset{0U}; - auto segment_id_result = - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); - auto offset_result = - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); - - if (!segment_id_result.has_value() || !offset_result.has_value()) + auto result = convert_id_and_offset(receiveBuffer); + + if (!result) { - IOX_LOG(ERROR, "conversion failed!"); return nullptr; } - segmentId = segment_id_result.value(); - offset = offset_result.value(); - auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); + auto [segment_id, offset] = result.value(); + + auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segment_id}, offset); return reinterpret_cast(ptr); } } @@ -647,22 +617,16 @@ NodeData* PoshRuntimeImpl::createNode(const NodeProperty& nodeProperty) noexcept if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_NODE_ACK) { - segment_id_underlying_t segmentId{0U}; - UntypedRelativePointer::offset_t offset{0U}; - auto segment_id_result = - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); - auto offset_result = - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); - - if (!segment_id_result.has_value() || !offset_result.has_value()) + auto result = convert_id_and_offset(receiveBuffer); + + if (!result) { - IOX_LOG(ERROR, "conversion failed!"); return nullptr; } - segmentId = segment_id_result.value(); - offset = offset_result.value(); - auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); + auto [segment_id, offset] = result.value(); + + auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segment_id}, offset); return reinterpret_cast(ptr); } } @@ -687,22 +651,16 @@ PoshRuntimeImpl::requestConditionVariableFromRoudi(const IpcMessage& sendBuffer) if (stringToIpcMessageType(IpcMessage.c_str()) == IpcMessageType::CREATE_CONDITION_VARIABLE_ACK) { - segment_id_underlying_t segmentId{0U}; - UntypedRelativePointer::offset_t offset{0U}; - auto segment_id_result = - convert::from_string(receiveBuffer.getElementAtIndex(2U).c_str()); - auto offset_result = - convert::from_string(receiveBuffer.getElementAtIndex(1U).c_str()); - - if (!segment_id_result.has_value() || !offset_result.has_value()) + auto result = convert_id_and_offset(receiveBuffer); + + if (!result) { - IOX_LOG(ERROR, "segment_id and/or offset conversion failed"); - return err(IpcMessageErrorType::SEGMENT_ID_OR_OFFSET_CONVERSION_FAILURE); + return err(result.error()); } - segmentId = segment_id_result.value(); - offset = offset_result.value(); - auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segmentId}, offset); + auto [segment_id, offset] = result.value(); + + auto ptr = UntypedRelativePointer::getPtr(segment_id_t{segment_id}, offset); return ok(reinterpret_cast(ptr)); } } @@ -805,5 +763,27 @@ void PoshRuntimeImpl::sendKeepAliveAndHandleShutdownPreparation() noexcept } } +expected, IpcMessageErrorType> +PoshRuntimeImpl::convert_id_and_offset(IpcMessage& msg) +{ + auto id = convert::from_string(msg.getElementAtIndex(2U).c_str()); + auto offset = convert::from_string(msg.getElementAtIndex(1U).c_str()); + + if (!id.has_value()) + { + IOX_LOG(ERROR, "segment_id conversion failed"); + return err(IpcMessageErrorType::SEGMENT_ID_CONVERSION_FAILURE); + } + + if (!offset.has_value()) + { + IOX_LOG(ERROR, "offset conversion failed"); + return err(IpcMessageErrorType::OFFSET_CONVERSION_FAILURE); + } + + return ok(std::make_tuple(id.value(), offset.value())); +} + + } // namespace runtime } // namespace iox From be1ab237f2d98b065fea6bddee45896f4d5907c9 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 02:09:01 +0800 Subject: [PATCH 19/33] iox-#2055 Improve error msg Now, `is_valid_errno` will also print the string that cause failure. Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 2 +- .../utility/include/iox/detail/convert.inl | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index e529e8f968..b99d099e1a 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -155,7 +155,7 @@ class convert /// a common error scenario during string-to-numeric conversion. /// @param errno_cache Cached errno value to be checked. /// @return True if errno does not indicate an error, false otherwise. - static bool is_valid_errno(decltype(errno) errno_cache) noexcept; + static bool is_valid_errno(decltype(errno) errno_cache, const char* str) noexcept; /// @brief Checks if the given value is within the allowable range for the target type. diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 9e959481a7..fdc44b10a3 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -307,7 +307,7 @@ inline bool convert::check_edge_case(decltype(errno) errno_cache, const char* v, const RequireCheckValType& require_check_val) noexcept { - return is_valid_input(end_ptr, v, require_check_val) && is_valid_errno(errno_cache) + return is_valid_input(end_ptr, v, require_check_val) && is_valid_errno(errno_cache, v) && is_within_range(require_check_val); } @@ -349,18 +349,24 @@ convert::is_valid_input(const char* end_ptr, const char* v, const RequireCheckVa return true; } -inline bool convert::is_valid_errno(decltype(errno) errno_cache) noexcept +inline bool convert::is_valid_errno(decltype(errno) errno_cache, const char* str) noexcept { // check errno if (errno_cache == ERANGE) { - IOX_LOG(DEBUG, "ERANGE triggered during conversion"); + IOX_LOG(DEBUG, "ERANGE triggered during conversion of string: " << str); return false; } if (errno_cache == EINVAL) { - IOX_LOG(DEBUG, "EINVAL triggered during conversion"); + IOX_LOG(DEBUG, "EINVAL triggered during conversion of string: " << str); + return false; + } + + if (errno_cache != 0) + { + IOX_LOG(DEBUG, "Unexpected errno: " << errno_cache << ". The input string is: " << str); return false; } From 61232c1a073e853e494374611128d12e9370c214 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 11:07:17 +0800 Subject: [PATCH 20/33] iox-#2055 Use type alias to make code more concise Signed-off-by: Dennis Liu --- iceoryx_posh/source/runtime/ipc_interface_base.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index 158164bcee..8fe2fc8368 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -39,8 +39,8 @@ IpcMessageType stringToIpcMessageType(const char* str) noexcept msg = result.value(); - if (static_cast::type>(IpcMessageType::BEGIN) >= msg - || static_cast::type>(IpcMessageType::END) <= msg) + if (static_cast(IpcMessageType::BEGIN) >= msg + || static_cast(IpcMessageType::END) <= msg) { return IpcMessageType::NOTYPE; } @@ -50,8 +50,8 @@ IpcMessageType stringToIpcMessageType(const char* str) noexcept // // XXX We would like to write code in the following way but failed // // The return type of result.and_then seems have to be the same with input type // return result.and_then([](const auto& msg) { - // if (static_cast::type>(IpcMessageType::BEGIN) >= msg - // || static_cast::type>(IpcMessageType::END) <= msg) { + // if (static_cast(IpcMessageType::BEGIN) >= msg + // || static_cast(IpcMessageType::END) <= msg) { // return iox::optional{}; // } // return iox::optional{static_cast(msg)}; @@ -61,7 +61,8 @@ IpcMessageType stringToIpcMessageType(const char* str) noexcept std::string IpcMessageTypeToString(const IpcMessageType msg) noexcept { - return convert::toString(static_cast::type>(msg)); + using UnderlyingType = std::underlying_type::type; + return convert::toString(static_cast(msg)); } IpcMessageErrorType stringToIpcMessageErrorType(const char* str) noexcept From 3ff3c739d4af9c6db2b2d1708d3f968e2d874db4 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 12:42:09 +0800 Subject: [PATCH 21/33] iox-#2055 Refine `from_string` specialization - Add long and unsigned long specialization for from_string. - Remove deprecated `is_iox_string` and `GetCapacity`. - Move the specialization of std::string to `iox/std_string_support.hpp`. - Replace `enable_if_t` by `if constexpr` branch. Signed-off-by: Dennis Liu --- .../test/moduletests/test_utility_convert.cpp | 1 + .../utility/include/iox/detail/convert.hpp | 109 ++---------------- .../utility/include/iox/detail/convert.inl | 62 ++++++++-- .../include/iox/std_string_support.hpp | 12 ++ 4 files changed, 73 insertions(+), 111 deletions(-) diff --git a/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp b/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp index 0117a7bac3..4121465687 100644 --- a/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp +++ b/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp @@ -18,6 +18,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "iox/detail/convert.hpp" +#include "iox/std_string_support.hpp" #include "test.hpp" diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index b99d099e1a..15979e538f 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -76,126 +76,37 @@ class convert static typename std::enable_if::value, std::string>::type toString(const Source& t) noexcept; - /// @brief Sets dest from a given string. If the conversion fails false is - /// returned and the value of dest is undefined. - /// @param[in] v string which contains the value of dest - /// @param[in] dest destination to which the value should be written - /// @return false = if the conversion fails otherwise true - template ::value, int> = 0> - static iox::optional from_string(const char* v) noexcept; - - /// @brief for those not Destination not string - /// @tparam Destination - /// @param v - /// @return - template ::value, int> = 0> + /// @brief convert the input based on the 'Destination', allowing only 'iox::string' and numeric types as valid + /// destination types + /// @note for the 'Destination' equal to 'std::string,' please include 'iox/std_string_support.hpp' + /// @tparam Destination the desired target type for converting text + /// @param v the input string in c type + /// @return an iox::optional where, if the return value is iox::nullopt, it indicates a failed + /// conversion process + template static iox::optional from_string(const char* v) noexcept; private: - /// @brief Evaluates the return value from a POSIX call or similar function call. - /// This function checks if the call resulted in an error and validates the edge cases - /// of the conversion from string to a numeric value. It returns an optional containing - /// the converted value if successful, or nullopt if there's an error or edge case failure. - /// @tparam TargetType The type to which the string is being converted. - /// @tparam CallType The type of the call object. - /// @param call Reference to the call object. - /// @param errno_cache Cached errno value for error checking. - /// @param end_ptr Pointer to the character after the last character used in the conversion. - /// @param v Pointer to the input string. - /// @return Optional containing the converted value or nullopt. template static iox::optional evaluate_return_value(CallType& call, decltype(errno) errno_cache, const char* end_ptr, const char* v) noexcept; - /// @brief Checks for edge cases in string conversion to a numeric type. - /// This function evaluates various conditions that might indicate an edge - /// case or an error in the conversion process from a string to a numeric type. - /// It checks for invalid input strings, conversion failures, errors indicated - /// by 'errno', and whether the converted value falls within the expected range. - /// @tparam TargetType The numeric type to which the string is being converted. - /// @tparam RequireCheckValType The type of the value being checked against edge cases. - /// @param errno_cache Cached value of 'errno' to check for conversion errors. - /// @param end_ptr Pointer to the character following the last character used - /// in the conversion, used to check for conversion failures. - /// @param v Pointer to the input string being converted. - /// @param require_check_val The value to be checked against edge cases. - /// @return True if no edge cases or errors are detected, false otherwise. template static bool check_edge_case(decltype(errno) errno_cache, const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept; - /// @brief Determines if a given string starts with a negative sign after skipping any leading spaces. - /// This function examines the input string and returns true if the first non-space character - /// is a negative sign ('-'). It is useful for parsing strings representing numeric values, - /// where the sign of the number needs to be determined. - /// @param v Pointer to the null-terminated input string to be checked. - /// @return True if the string starts with a negative sign after any leading spaces, false otherwise. - - static bool start_with_neg_sign(const char* v) noexcept; - - /// @brief Checks if the string input is valid based on the results of its conversion. - /// This function determines the validity of the input string by analyzing the outcome - /// of a conversion function like strtoull. It checks whether the end_ptr overlaps with - /// the beginning of v, indicating no conversion occurred, or if the conversion did not - /// terminate at a null character '\0', both scenarios being indicative of an invalid input. - /// @tparam RequireCheckValType Type of the value being checked. - /// @param end_ptr Pointer to the character after the last character used in the conversion. - /// @param v Pointer to the input string. - /// @param require_check_val The value obtained from the conversion, used for comparison. - /// @return True if the input is valid for conversion, false otherwise. template static bool is_valid_input(const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept; - - /// @brief Checks if the cached errno indicates a valid conversion. - /// This function assesses the errno value to determine if it represents - /// a common error scenario during string-to-numeric conversion. - /// @param errno_cache Cached errno value to be checked. - /// @return True if errno does not indicate an error, false otherwise. - static bool is_valid_errno(decltype(errno) errno_cache, const char* str) noexcept; - - - /// @brief Checks if the given value is within the allowable range for the target type. - /// This function evaluates whether the specified value falls within the numeric limits - /// of the target type, considering both upper and lower bounds. - /// @tparam TargetType The numeric type to be checked against. - /// @tparam RequireCheckValType Type of the value being checked. - /// @param require_check_val The value to be evaluated against the target type's range. - /// @return True if the value is within range, false otherwise. template static bool is_within_range(const RequireCheckValType& require_check_val) noexcept; + static bool start_with_neg_sign(const char* v) noexcept; - /// @todo iox-#2055 I believe there's a more elegant way to implement this. What do you think? - private: - /// @brief Trait struct to determine if a type is an iox::string. - /// Provides a compile-time check to identify if a given type is an instance of iox::string. - /// @tparam T Type to be checked. - template - struct is_iox_string : std::false_type - { - }; - - /// Specialization of is_iox_string for iox::string. - template - struct is_iox_string> : std::true_type - { - }; - - /// @brief Helper struct to extract the capacity of an iox::string at compile time. - /// Provides a mechanism to obtain the capacity of an iox::string type. - template - struct GetCapacity; - - /// Specialization of GetCapacity for iox::string. - template - struct GetCapacity> - { - static constexpr uint64_t value = Capacity; - }; + static bool is_valid_errno(decltype(errno) errno_cache, const char* str) noexcept; }; } // namespace iox diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index fdc44b10a3..57ef8df627 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -21,6 +21,7 @@ #define IOX_HOOFS_UTILITY_CONVERT_INL #include "iox/detail/convert.hpp" +#include "iox/detail/string_type_traits.hpp" #include "iox/logging.hpp" namespace iox @@ -58,10 +59,24 @@ convert::toString(const Source& t) noexcept return t; } -template ::value, int>> +template inline iox::optional convert::from_string(const char* v) noexcept { - return iox::optional(Destination(v)); + if constexpr (is_iox_string::value) + { + using IoxString = Destination; + if (strlen(v) > IoxString::capacity()) + { + return iox::nullopt; + } + return iox::optional(IoxString(TruncateToCapacity, v)); + } + else + { + static_assert(always_false_v, + "For a conversion to 'std::string' please include 'iox/std_string_support.hpp'!\nConversion not " + "supported!"); + } } template <> @@ -78,16 +93,6 @@ inline iox::optional convert::from_string(const char* v) noexcept return iox::optional(v[0]); } -template ::value, int>> -inline iox::optional convert::from_string(const char* v) noexcept -{ - if (strlen(v) > GetCapacity::value) - { - return iox::nullopt; - } - return iox::optional(IoxString(TruncateToCapacity, v)); -} - template <> inline iox::optional convert::from_string(const char* v) noexcept { @@ -171,6 +176,25 @@ inline iox::optional convert::from_string(call, errno, end_ptr, v); } +template <> +inline iox::optional convert::from_string(const char* v) noexcept +{ + errno = 0; + char* end_ptr = nullptr; + + if (start_with_neg_sign(v)) + { + return iox::nullopt; + } + + auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(ULLONG_MAX) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); + + return evaluate_return_value(call, errno, end_ptr, v); +} + template <> inline iox::optional convert::from_string(const char* v) noexcept { @@ -242,6 +266,20 @@ inline iox::optional convert::from_string(const char* v) n return evaluate_return_value(call, errno, end_ptr, v); } +template <> +inline iox::optional convert::from_string(const char* v) noexcept +{ + errno = 0; + char* end_ptr = nullptr; + + auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE) + .failureReturnValue(LLONG_MAX, LLONG_MIN) + .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .evaluate(); + + return evaluate_return_value(call, errno, end_ptr, v); +} + template <> inline iox::optional convert::from_string(const char* v) noexcept { diff --git a/iceoryx_hoofs/utility/include/iox/std_string_support.hpp b/iceoryx_hoofs/utility/include/iox/std_string_support.hpp index 28f1a89173..6a4f5a35c5 100644 --- a/iceoryx_hoofs/utility/include/iox/std_string_support.hpp +++ b/iceoryx_hoofs/utility/include/iox/std_string_support.hpp @@ -17,6 +17,7 @@ #ifndef IOX_HOOFS_UTILITY_STD_STRING_SUPPORT_HPP #define IOX_HOOFS_UTILITY_STD_STRING_SUPPORT_HPP +#include "iox/detail/convert.hpp" #include "iox/into.hpp" #include "iox/optional.hpp" #include "iox/string.hpp" @@ -88,6 +89,17 @@ struct FromImpl>> /// @return the stream output of the fixed string template std::ostream& operator<<(std::ostream& stream, const string& str) noexcept; + +/// @brief A specialization function of convert::from_string for std::string +/// @param v the input string in c type +/// @return an iox::optional where, if the return value is iox::nullopt, it indicates a failed conversion +/// process +template <> +inline iox::optional convert::from_string(const char* v) noexcept +{ + return iox::optional(v); +} + } // namespace iox #include "iox/detail/std_string_support.inl" From 79cac77af2d633ec1859af1f58e0353a535b11ea Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 15:36:26 +0800 Subject: [PATCH 22/33] iox-#2055 Replace post-increment with pre-increment Signed-off-by: Dennis Liu --- iceoryx_hoofs/utility/include/iox/detail/convert.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 57ef8df627..09ad604587 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -333,7 +333,7 @@ inline bool convert::start_with_neg_sign(const char* v) noexcept while (*v != '\0' && (isspace((unsigned char)*v) != 0)) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - v++; + ++v; } return (*v == '-'); From 5ab15f5f28afc5cebd79e7f4b137b7c5c83510d9 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 16:03:34 +0800 Subject: [PATCH 23/33] iox-#2055 Rename to SourceType and source_val Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 13 ++++---- .../utility/include/iox/detail/convert.inl | 31 +++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index 15979e538f..4d6ad98437 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -91,18 +91,17 @@ class convert static iox::optional evaluate_return_value(CallType& call, decltype(errno) errno_cache, const char* end_ptr, const char* v) noexcept; - template + template static bool check_edge_case(decltype(errno) errno_cache, const char* end_ptr, const char* v, - const RequireCheckValType& require_check_val) noexcept; + const SourceType& source_val) noexcept; - template - static bool - is_valid_input(const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept; + template + static bool is_valid_input(const char* end_ptr, const char* v, const SourceType& source_val) noexcept; - template - static bool is_within_range(const RequireCheckValType& require_check_val) noexcept; + template + static bool is_within_range(const SourceType& source_val) noexcept; static bool start_with_neg_sign(const char* v) noexcept; diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 09ad604587..947bedf3b9 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -339,14 +339,14 @@ inline bool convert::start_with_neg_sign(const char* v) noexcept return (*v == '-'); } -template +template inline bool convert::check_edge_case(decltype(errno) errno_cache, const char* end_ptr, const char* v, - const RequireCheckValType& require_check_val) noexcept + const SourceType& source_val) noexcept { - return is_valid_input(end_ptr, v, require_check_val) && is_valid_errno(errno_cache, v) - && is_within_range(require_check_val); + return is_valid_input(end_ptr, v, source_val) && is_valid_errno(errno_cache, v) + && is_within_range(source_val); } template @@ -366,12 +366,11 @@ convert::evaluate_return_value(CallType& call, decltype(errno) errno_cache, cons return iox::optional(static_cast(call->value)); } -template -inline bool -convert::is_valid_input(const char* end_ptr, const char* v, const RequireCheckValType& require_check_val) noexcept +template +inline bool convert::is_valid_input(const char* end_ptr, const char* v, const SourceType& source_val) noexcept { // invalid string - if (v == end_ptr && require_check_val == 0) + if (v == end_ptr && source_val == 0) { IOX_LOG(DEBUG, "invalid input"); return false; @@ -411,26 +410,26 @@ inline bool convert::is_valid_errno(decltype(errno) errno_cache, const char* str return true; } -template -inline bool convert::is_within_range(const RequireCheckValType& require_check_val) noexcept +template +inline bool convert::is_within_range(const SourceType& source_val) noexcept { if constexpr (std::is_arithmetic_v) { // out of range (upper bound) - if (require_check_val > std::numeric_limits::max()) + if (source_val > std::numeric_limits::max()) { IOX_LOG(DEBUG, - require_check_val << " is out of range (upper bound), should be less than " - << std::numeric_limits::max()); + source_val << " is out of range (upper bound), should be less than " + << std::numeric_limits::max()); return false; } // out of range (lower bound) - if (require_check_val < std::numeric_limits::lowest()) + if (source_val < std::numeric_limits::lowest()) { IOX_LOG(DEBUG, - require_check_val << " is out of range (lower bound), should be larger than " - << std::numeric_limits::lowest()); + source_val << " is out of range (lower bound), should be larger than " + << std::numeric_limits::lowest()); return false; } } From 640c0105a452fcd68cac05291e5ef3b4ea84c8d9 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 16:04:04 +0800 Subject: [PATCH 24/33] iox-#2055 Use assertion for `has_value` check Signed-off-by: Dennis Liu --- .../test/moduletests/test_utility_convert.cpp | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp b/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp index 4121465687..c2cd543ec5 100644 --- a/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp +++ b/iceoryx_hoofs/test/moduletests/test_utility_convert.cpp @@ -111,7 +111,7 @@ TEST_F(convert_test, FromString_String) ::testing::Test::RecordProperty("TEST_ID", "22463da5-0fcb-4aa2-a7e5-68b863278a81"); std::string source = "hello"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(source)); } @@ -120,7 +120,7 @@ TEST_F(convert_test, fromString_Char_Success) ::testing::Test::RecordProperty("TEST_ID", "a15825c9-536a-4671-a502-6973490022e7"); std::string source = "h"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(source[0])); } @@ -129,7 +129,7 @@ TEST_F(convert_test, fromString_Char_Fail) ::testing::Test::RecordProperty("TEST_ID", "656e87ad-6fdb-42d7-bf49-23f81a4f5a31"); std::string source = "hasd"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_FLOAT_Success) @@ -137,7 +137,7 @@ TEST_F(convert_test, fromString_FLOAT_Success) ::testing::Test::RecordProperty("TEST_ID", "d6255c3e-369e-43a0-a1ab-03f7b13d03c2"); std::string source = "123.01"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_FLOAT_EQ(result.value(), 123.01F); } @@ -146,7 +146,7 @@ TEST_F(convert_test, fromString_FLOAT_Fail) ::testing::Test::RecordProperty("TEST_ID", "e2b94d50-664c-4f9e-be4f-99212c6fa165"); std::string source = "hasd"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_Double_Success) @@ -154,7 +154,7 @@ TEST_F(convert_test, fromString_Double_Success) ::testing::Test::RecordProperty("TEST_ID", "95ba379e-120e-4b80-a829-33fe54f1bfed"); std::string source = "123.04"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), DoubleEq(123.04)); } @@ -163,7 +163,7 @@ TEST_F(convert_test, fromString_Double_Fail) ::testing::Test::RecordProperty("TEST_ID", "f4ace11b-a056-47b1-b6c5-6fb2c58e1a06"); std::string source = "hasd"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_LongDouble_Success) @@ -172,7 +172,7 @@ TEST_F(convert_test, fromString_LongDouble_Success) std::string source = "121.01"; constexpr long double VERIFY = 121.01; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(static_cast(result.value()), DoubleEq(static_cast(VERIFY))); } @@ -181,7 +181,7 @@ TEST_F(convert_test, fromString_LongDouble_Fail) ::testing::Test::RecordProperty("TEST_ID", "519f2ac5-8836-419e-8034-377230a88a09"); std::string source = "hasd"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_UNSIGNED_Int_Success) @@ -189,7 +189,7 @@ TEST_F(convert_test, fromString_UNSIGNED_Int_Success) ::testing::Test::RecordProperty("TEST_ID", "1edb8d5f-c42d-4d02-bc31-477f48898bbb"); std::string source = "100"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(100U)); } @@ -198,7 +198,7 @@ TEST_F(convert_test, fromString_UNSIGNED_Int_Fail) ::testing::Test::RecordProperty("TEST_ID", "6ce6de82-a6c0-4562-9c5c-663b93d768b3"); std::string source = "-331"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_UNSIGNED_LongInt_Success) @@ -206,7 +206,7 @@ TEST_F(convert_test, fromString_UNSIGNED_LongInt_Success) ::testing::Test::RecordProperty("TEST_ID", "054b08b2-54e1-4191-91b6-e6bec415612f"); std::string source = "999"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(999LU)); } @@ -215,7 +215,7 @@ TEST_F(convert_test, fromString_UNSIGNED_LongInt_Fail) ::testing::Test::RecordProperty("TEST_ID", "4b215747-90b2-4ca2-97ee-517c07597b1b"); std::string source = "-a123"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_Int_Success) @@ -223,7 +223,7 @@ TEST_F(convert_test, fromString_Int_Success) ::testing::Test::RecordProperty("TEST_ID", "9318ee60-f2e0-445a-b32d-c718cf918b18"); std::string source = "3331"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(3331)); } @@ -232,7 +232,7 @@ TEST_F(convert_test, fromString_Int_Fail) ::testing::Test::RecordProperty("TEST_ID", "f8e698a9-054d-4441-b196-bcd58a72b1d9"); std::string source = "-+321"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_ShortInt_Success) @@ -240,7 +240,7 @@ TEST_F(convert_test, fromString_ShortInt_Success) ::testing::Test::RecordProperty("TEST_ID", "e804f821-157d-4c52-81a7-75fce5a43805"); std::string source = "12345"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(12345)); } @@ -249,7 +249,7 @@ TEST_F(convert_test, fromString_ShortInt_Fail) ::testing::Test::RecordProperty("TEST_ID", "1150066b-cb42-4055-9927-2f20fb40bc87"); std::string source = "-+123321"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_Bool_Success) @@ -257,7 +257,7 @@ TEST_F(convert_test, fromString_Bool_Success) ::testing::Test::RecordProperty("TEST_ID", "893723fc-dfb8-46a4-b446-badaf8bad25a"); std::string source = "1"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(true)); } @@ -266,7 +266,7 @@ TEST_F(convert_test, fromString_Bool_Fail) ::testing::Test::RecordProperty("TEST_ID", "1c937da6-29ea-49cf-a7d0-4c46f564c16e"); std::string source = "-+222"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_UShortInt_Success) @@ -274,7 +274,7 @@ TEST_F(convert_test, fromString_UShortInt_Success) ::testing::Test::RecordProperty("TEST_ID", "99d22d80-3860-47fa-9f98-f11ff9629815"); std::string source = "333"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(333)); } @@ -283,7 +283,7 @@ TEST_F(convert_test, fromString_UShortInt_Fail) ::testing::Test::RecordProperty("TEST_ID", "6ab6ded6-dff3-401a-8a7f-98326da7cca6"); std::string source = "-+111"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_LongInt_Success) @@ -291,7 +291,7 @@ TEST_F(convert_test, fromString_LongInt_Success) ::testing::Test::RecordProperty("TEST_ID", "37133256-ae79-45c7-8c86-56bd33fa7bd8"); std::string source = "-1123"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(true)); + ASSERT_THAT(result.has_value(), Eq(true)); EXPECT_THAT(result.value(), Eq(-1123L)); } @@ -300,7 +300,7 @@ TEST_F(convert_test, fromString_LongInt_Fail) ::testing::Test::RecordProperty("TEST_ID", "0e368bf3-cb16-4829-a4cc-dc56e0bde958"); std::string source = "-a121"; auto result = iox::convert::from_string(source.c_str()); - EXPECT_THAT(result.has_value(), Eq(false)); + ASSERT_THAT(result.has_value(), Eq(false)); } TEST_F(convert_test, fromString_MinMaxShort) From e83b76d543953b8a2e272e5f7ba5456ecf1e8c06 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 16:45:43 +0800 Subject: [PATCH 25/33] iox-#2055 Add a todo in `is_valid_errno` - Add a todo in `is_valid_errno`. - Clean `errno` before leaving from `evaluate return value`. Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 5 +-- .../utility/include/iox/detail/convert.inl | 31 ++++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index 4d6ad98437..53e0c50d29 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -103,9 +103,10 @@ class convert template static bool is_within_range(const SourceType& source_val) noexcept; - static bool start_with_neg_sign(const char* v) noexcept; + template + static bool is_valid_errno(decltype(errno) errno_cache, const char* v, const SourceType& source_val) noexcept; - static bool is_valid_errno(decltype(errno) errno_cache, const char* str) noexcept; + static bool start_with_neg_sign(const char* v) noexcept; }; } // namespace iox diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 947bedf3b9..94bb26a430 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -345,7 +345,7 @@ inline bool convert::check_edge_case(decltype(errno) errno_cache, const char* v, const SourceType& source_val) noexcept { - return is_valid_input(end_ptr, v, source_val) && is_valid_errno(errno_cache, v) + return is_valid_input(end_ptr, v, source_val) && is_valid_errno(errno_cache, v, source_val) && is_within_range(source_val); } @@ -363,6 +363,9 @@ convert::evaluate_return_value(CallType& call, decltype(errno) errno_cache, cons return iox::nullopt; } + // clean errno + errno = 0; + return iox::optional(static_cast(call->value)); } @@ -386,24 +389,42 @@ inline bool convert::is_valid_input(const char* end_ptr, const char* v, const So return true; } -inline bool convert::is_valid_errno(decltype(errno) errno_cache, const char* str) noexcept +template +inline bool convert::is_valid_errno(decltype(errno) errno_cache, const char* v, const SourceType& source_val) noexcept { // check errno if (errno_cache == ERANGE) { - IOX_LOG(DEBUG, "ERANGE triggered during conversion of string: " << str); + if constexpr (std::is_floating_point_v) + { + /// @todo iox-#2055 + // This could be a case of 'inf' or 'nan' for floating points, + // yet the use of 'failureReturnValue' effectively prevents the occurrence of 'inf'. + // In such instances, due to 'result.has_error' being true, + // 'from_string' will return prematurely. + // Consequently, this function will remain uncalled. + + // currently, we still treat them as conversion error + // but they should be treated as potential result (instead of error)? + IOX_LOG(DEBUG, + "ERANGE triggered during conversion of string: '" << v << "'. The result is: " << source_val); + } + else + { + IOX_LOG(DEBUG, "ERANGE triggered during conversion of string: '" << v << "'"); + } return false; } if (errno_cache == EINVAL) { - IOX_LOG(DEBUG, "EINVAL triggered during conversion of string: " << str); + IOX_LOG(DEBUG, "EINVAL triggered during conversion of string: " << v); return false; } if (errno_cache != 0) { - IOX_LOG(DEBUG, "Unexpected errno: " << errno_cache << ". The input string is: " << str); + IOX_LOG(DEBUG, "Unexpected errno: " << errno_cache << ". The input string is: " << v); return false; } From 3afbea98e9f38108f7bd841d1985de24ced4fe67 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Thu, 21 Dec 2023 21:22:22 +0800 Subject: [PATCH 26/33] iox-#2055 Modify the function IOX_POSIX_CALL call Modify the target function of the `IOX_POSIX_CALL` invocation, and for those that might encounter an edge case error due to the invocation of `failureReturnValue`, replace it with `alwaysSuccess`. Specifically, this applies to unsigned/signed types: `long long`, `long`, and `int` (for 32-bit systems). Please note that we assume `int` is always 4 bytes, and `long long` is definitively 8 bytes. Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 5 +++- .../utility/include/iox/detail/convert.inl | 30 ++++++++++--------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index 53e0c50d29..11e9c69c77 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -56,7 +56,10 @@ class convert FLOAT }; - static constexpr int32_t STRTOULL_BASE = 10; + static constexpr int32_t STRTOULL_BASE{10}; + static constexpr int32_t STRTOUL_BASE{10}; + static constexpr int32_t STRTOLL_BASE{10}; + static constexpr int32_t STRTOL_BASE{10}; /// @brief Converts every type which is either a pod (plain old data) type or is convertable /// to a string (this means that the operator std::string() is defined) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 94bb26a430..6fa295177e 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -105,7 +105,7 @@ inline iox::optional convert::from_string(const char* v) noexcept return iox::nullopt; } - auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOUL_BASE) .failureReturnValue(ULONG_MAX) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -187,8 +187,8 @@ inline iox::optional convert::from_string(const ch return iox::nullopt; } - auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) - .failureReturnValue(ULLONG_MAX) + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOUL_BASE) + .alwaysSuccess() .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -206,8 +206,9 @@ inline iox::optional convert::from_string(const char return iox::nullopt; } - auto call = IOX_POSIX_CALL(strtoull)(v, &end_ptr, STRTOULL_BASE) - .failureReturnValue(ULLONG_MAX) + // use alwaysSuccess for the conversion edge cases in 32-bit system? + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOUL_BASE) + .alwaysSuccess() .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -225,7 +226,7 @@ inline iox::optional convert::from_string(const return iox::nullopt; } - auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) + auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOUL_BASE) .failureReturnValue(ULONG_MAX) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -258,8 +259,8 @@ inline iox::optional convert::from_string(const char* v) n errno = 0; char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE) - .failureReturnValue(LLONG_MAX, LLONG_MIN) + auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOLL_BASE) + .alwaysSuccess() .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -272,8 +273,8 @@ inline iox::optional convert::from_string(const char* v) noexcept errno = 0; char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE) - .failureReturnValue(LLONG_MAX, LLONG_MIN) + auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) + .alwaysSuccess() .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -286,8 +287,9 @@ inline iox::optional convert::from_string(const char* v) noexcept errno = 0; char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOULL_BASE) - .failureReturnValue(LLONG_MAX, LLONG_MIN) + // use alwaysSuccess for the conversion edge cases in 32-bit system? + auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) + .alwaysSuccess() .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -300,7 +302,7 @@ inline iox::optional convert::from_string(const char* v) noexcept errno = 0; char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE) + auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) .failureReturnValue(LONG_MAX, LONG_MIN) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); @@ -314,7 +316,7 @@ inline iox::optional convert::from_string(const char* errno = 0; char* end_ptr = nullptr; - auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOULL_BASE) + auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) .failureReturnValue(LONG_MAX, LONG_MIN) .suppressErrorMessagesForErrnos(EINVAL, ERANGE) .evaluate(); From 3defd1e3954694e8e943d9ed09b365ec55a8f096 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Sun, 24 Dec 2023 21:00:59 +0800 Subject: [PATCH 27/33] iox-#2055 Remove alwaysSuccess Signed-off-by: Dennis Liu --- .../design/include/iox/detail/posix_call.inl | 7 --- .../posix/design/include/iox/posix_call.hpp | 10 ----- .../utility/include/iox/detail/convert.inl | 43 +++++++++---------- 3 files changed, 20 insertions(+), 40 deletions(-) diff --git a/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl b/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl index c93b780fff..5c9ccf135c 100644 --- a/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl +++ b/iceoryx_hoofs/posix/design/include/iox/detail/posix_call.inl @@ -146,13 +146,6 @@ inline PosixCallEvaluator PosixCallVerificator::returnVa return PosixCallEvaluator(m_details); } -template -inline PosixCallEvaluator PosixCallVerificator::alwaysSuccess() && noexcept -{ - m_details.hasSuccess = true; - return PosixCallEvaluator(m_details); -} - template inline PosixCallEvaluator::PosixCallEvaluator(detail::PosixCallDetails& details) noexcept : m_details{details} diff --git a/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp b/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp index 5d196a5fee..4a950d47cb 100644 --- a/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp +++ b/iceoryx_hoofs/posix/design/include/iox/posix_call.hpp @@ -132,16 +132,6 @@ class [[nodiscard]] PosixCallVerificator /// @return the PosixCallEvaluator which evaluates the errno values PosixCallEvaluator returnValueMatchesErrno() && noexcept; - /// @brief Sets the POSIX call to always be treated as successful. - /// @details This function marks the current POSIX call evaluation as always successful, - /// regardless of the actual outcome. It is particularly useful in scenarios - /// where the return value or error state should be ignored, and the operation - /// should always be considered successful. - /// @tparam ReturnType The return type of the POSIX call. - /// @return An instance of PosixCallEvaluator that represents the modified - /// state of the POSIX call evaluation, with success status enforced. - PosixCallEvaluator alwaysSuccess() && noexcept; - private: template friend class PosixCallBuilder; diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 6fa295177e..5bfc7ee34f 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -107,7 +107,7 @@ inline iox::optional convert::from_string(const char* v) noexcept auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOUL_BASE) .failureReturnValue(ULONG_MAX) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); // we assume that in the IOX_POSIX_CALL procedure, no other POSIX call will change errno, @@ -123,7 +123,7 @@ inline iox::optional convert::from_string(const char* v) noexcept auto call = IOX_POSIX_CALL(strtof)(v, &end_ptr) .failureReturnValue(HUGE_VALF, -HUGE_VALF) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -137,7 +137,7 @@ inline iox::optional convert::from_string(const char* v) noexcep auto call = IOX_POSIX_CALL(strtod)(v, &end_ptr) .failureReturnValue(HUGE_VAL, -HUGE_VAL) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -151,7 +151,7 @@ inline iox::optional convert::from_string(const char* auto call = IOX_POSIX_CALL(strtold)(v, &end_ptr) .failureReturnValue(HUGE_VALL, -HUGE_VALL) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -169,8 +169,8 @@ inline iox::optional convert::from_string(call, errno, end_ptr, v); @@ -188,8 +188,8 @@ inline iox::optional convert::from_string(const ch } auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOUL_BASE) - .alwaysSuccess() - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .failureReturnValue(ULONG_MAX) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -208,8 +208,8 @@ inline iox::optional convert::from_string(const char // use alwaysSuccess for the conversion edge cases in 32-bit system? auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOUL_BASE) - .alwaysSuccess() - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .failureReturnValue(ULONG_MAX) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -228,7 +228,7 @@ inline iox::optional convert::from_string(const auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOUL_BASE) .failureReturnValue(ULONG_MAX) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -247,7 +247,7 @@ inline iox::optional convert::from_string(const ch auto call = IOX_POSIX_CALL(strtoul)(v, &end_ptr, STRTOULL_BASE) .failureReturnValue(ULONG_MAX) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -260,8 +260,8 @@ inline iox::optional convert::from_string(const char* v) n char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOLL_BASE) - .alwaysSuccess() - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .failureReturnValue(LLONG_MAX, LLONG_MIN) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -274,8 +274,8 @@ inline iox::optional convert::from_string(const char* v) noexcept char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) - .alwaysSuccess() - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .failureReturnValue(LONG_MAX, LONG_MIN) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -289,8 +289,8 @@ inline iox::optional convert::from_string(const char* v) noexcept // use alwaysSuccess for the conversion edge cases in 32-bit system? auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) - .alwaysSuccess() - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .failureReturnValue(LONG_MAX, LONG_MIN) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -304,7 +304,7 @@ inline iox::optional convert::from_string(const char* v) noexcept auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) .failureReturnValue(LONG_MAX, LONG_MIN) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -318,7 +318,7 @@ inline iox::optional convert::from_string(const char* auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) .failureReturnValue(LONG_MAX, LONG_MIN) - .suppressErrorMessagesForErrnos(EINVAL, ERANGE) + .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); return evaluate_return_value(call, errno, end_ptr, v); @@ -365,9 +365,6 @@ convert::evaluate_return_value(CallType& call, decltype(errno) errno_cache, cons return iox::nullopt; } - // clean errno - errno = 0; - return iox::optional(static_cast(call->value)); } From 809b9a9a880c14b1567cc76c47448abff90351de Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Mon, 25 Dec 2023 11:02:44 +0800 Subject: [PATCH 28/33] iox-#2055 Remove unused comment code Signed-off-by: Dennis Liu --- .../source/runtime/ipc_interface_base.cpp | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index 8fe2fc8368..adea4437fe 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -46,17 +46,6 @@ IpcMessageType stringToIpcMessageType(const char* str) noexcept } return static_cast(msg); - - // // XXX We would like to write code in the following way but failed - // // The return type of result.and_then seems have to be the same with input type - // return result.and_then([](const auto& msg) { - // if (static_cast(IpcMessageType::BEGIN) >= msg - // || static_cast(IpcMessageType::END) <= msg) { - // return iox::optional{}; - // } - // return iox::optional{static_cast(msg)}; - // }) - // .value_or(IpcMessageType::NOTYPE); } std::string IpcMessageTypeToString(const IpcMessageType msg) noexcept @@ -79,17 +68,6 @@ IpcMessageErrorType stringToIpcMessageErrorType(const char* str) noexcept } return static_cast(msg); - - // // XXX We would like to write code in the following way but failed - // // The return type of result.and_then seems have to be the same with input type - // return result.and_then([](const auto& msg) { - // if (static_cast::type>(IpcMessageErrorType::BEGIN) >= msg - // || static_cast::type>(IpcMessageErrorType::END) <= msg) { - // return iox::optional{}; - // } - // return iox::optional{static_cast(msg)}; - // }) - // .value_or(IpcMessageType::NOTYPE); } std::string IpcMessageErrorTypeToString(const IpcMessageErrorType msg) noexcept From 4706afe83c41e3bd8b99073381c567ddbfc98aab Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Mon, 25 Dec 2023 13:42:31 +0800 Subject: [PATCH 29/33] iox-#2055 Remove errno_cache from 'evaluate_return_value' Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 3 +- .../utility/include/iox/detail/convert.inl | 61 ++++++++----------- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index 11e9c69c77..498308ef13 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -91,8 +91,7 @@ class convert private: template - static iox::optional - evaluate_return_value(CallType& call, decltype(errno) errno_cache, const char* end_ptr, const char* v) noexcept; + static iox::optional evaluate_return_value(CallType& call, const char* end_ptr, const char* v) noexcept; template static bool check_edge_case(decltype(errno) errno_cache, diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 5bfc7ee34f..bb5f99f51c 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -112,7 +112,7 @@ inline iox::optional convert::from_string(const char* v) noexcept // we assume that in the IOX_POSIX_CALL procedure, no other POSIX call will change errno, // except for the target function 'f'. - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -126,7 +126,7 @@ inline iox::optional convert::from_string(const char* v) noexcept .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -140,7 +140,7 @@ inline iox::optional convert::from_string(const char* v) noexcep .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -154,7 +154,7 @@ inline iox::optional convert::from_string(const char* .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -173,7 +173,7 @@ inline iox::optional convert::from_string(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -192,7 +192,7 @@ inline iox::optional convert::from_string(const ch .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -212,7 +212,7 @@ inline iox::optional convert::from_string(const char .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -231,7 +231,7 @@ inline iox::optional convert::from_string(const .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -250,7 +250,7 @@ inline iox::optional convert::from_string(const ch .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -264,7 +264,7 @@ inline iox::optional convert::from_string(const char* v) n .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -278,7 +278,7 @@ inline iox::optional convert::from_string(const char* v) noexcept .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -293,7 +293,7 @@ inline iox::optional convert::from_string(const char* v) noexcept .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -307,7 +307,7 @@ inline iox::optional convert::from_string(const char* v) noexcept .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } template <> @@ -321,7 +321,7 @@ inline iox::optional convert::from_string(const char* .ignoreErrnos(0, EINVAL, ERANGE) .evaluate(); - return evaluate_return_value(call, errno, end_ptr, v); + return evaluate_return_value(call, end_ptr, v); } inline bool convert::start_with_neg_sign(const char* v) noexcept @@ -353,14 +353,14 @@ inline bool convert::check_edge_case(decltype(errno) errno_cache, template inline iox::optional -convert::evaluate_return_value(CallType& call, decltype(errno) errno_cache, const char* end_ptr, const char* v) noexcept +convert::evaluate_return_value(CallType& call, const char* end_ptr, const char* v) noexcept { if (call.has_error()) { return iox::nullopt; } - if (!check_edge_case(errno_cache, end_ptr, v, call->value)) + if (!check_edge_case(call->errnum, end_ptr, v, call->value)) { return iox::nullopt; } @@ -391,27 +391,9 @@ inline bool convert::is_valid_input(const char* end_ptr, const char* v, const So template inline bool convert::is_valid_errno(decltype(errno) errno_cache, const char* v, const SourceType& source_val) noexcept { - // check errno if (errno_cache == ERANGE) { - if constexpr (std::is_floating_point_v) - { - /// @todo iox-#2055 - // This could be a case of 'inf' or 'nan' for floating points, - // yet the use of 'failureReturnValue' effectively prevents the occurrence of 'inf'. - // In such instances, due to 'result.has_error' being true, - // 'from_string' will return prematurely. - // Consequently, this function will remain uncalled. - - // currently, we still treat them as conversion error - // but they should be treated as potential result (instead of error)? - IOX_LOG(DEBUG, - "ERANGE triggered during conversion of string: '" << v << "'. The result is: " << source_val); - } - else - { - IOX_LOG(DEBUG, "ERANGE triggered during conversion of string: '" << v << "'"); - } + IOX_LOG(DEBUG, "ERANGE triggered during conversion of string: '" << v << "'"); return false; } @@ -435,6 +417,15 @@ inline bool convert::is_within_range(const SourceType& source_val) noexcept { if constexpr (std::is_arithmetic_v) { + if constexpr (std::is_floating_point_v) + { + if (source_val == std::numeric_limits::signaling_NaN()) + { + IOX_LOG(DEBUG, "got signaling NaN"); + return false; + } + } + // out of range (upper bound) if (source_val > std::numeric_limits::max()) { From 3801cf50e9baf089a30e4e0fe102f18c59e469f4 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Mon, 25 Dec 2023 20:46:48 +0800 Subject: [PATCH 30/33] iox-#2055 Add 'is_signaling_nan' Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 6 +- .../utility/include/iox/detail/convert.inl | 155 ++++++++++++------ 2 files changed, 110 insertions(+), 51 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index 498308ef13..0482eb243b 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -61,6 +61,9 @@ class convert static constexpr int32_t STRTOLL_BASE{10}; static constexpr int32_t STRTOL_BASE{10}; + static constexpr uint32_t FLOAT_SIGNALING_NAN_MASK{static_cast(1) << static_cast(22)}; + static constexpr uint64_t DOUBLE_SIGNALING_NAN_MASK{static_cast(1) << static_cast(51)}; + /// @brief Converts every type which is either a pod (plain old data) type or is convertable /// to a string (this means that the operator std::string() is defined) /// @param Source type of the value which should be converted to a string @@ -106,8 +109,9 @@ class convert static bool is_within_range(const SourceType& source_val) noexcept; template - static bool is_valid_errno(decltype(errno) errno_cache, const char* v, const SourceType& source_val) noexcept; + static bool is_signaling_nan(const SourceType& source_val) noexcept; + static bool is_valid_errno(decltype(errno) errno_cache, const char* v) noexcept; static bool start_with_neg_sign(const char* v) noexcept; }; diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index bb5f99f51c..b561439a2c 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -324,30 +324,13 @@ inline iox::optional convert::from_string(const char* return evaluate_return_value(call, end_ptr, v); } -inline bool convert::start_with_neg_sign(const char* v) noexcept -{ - if (v == nullptr) - { - return false; - } - - // remove space - while (*v != '\0' && (isspace((unsigned char)*v) != 0)) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - ++v; - } - - return (*v == '-'); -} - template inline bool convert::check_edge_case(decltype(errno) errno_cache, const char* end_ptr, const char* v, const SourceType& source_val) noexcept { - return is_valid_input(end_ptr, v, source_val) && is_valid_errno(errno_cache, v, source_val) + return is_valid_input(end_ptr, v, source_val) && is_valid_errno(errno_cache, v) && is_within_range(source_val); } @@ -388,62 +371,134 @@ inline bool convert::is_valid_input(const char* end_ptr, const char* v, const So return true; } -template -inline bool convert::is_valid_errno(decltype(errno) errno_cache, const char* v, const SourceType& source_val) noexcept +template +inline bool convert::is_within_range(const SourceType& source_val) noexcept { - if (errno_cache == ERANGE) + if constexpr (std::is_arithmetic_v == false) { - IOX_LOG(DEBUG, "ERANGE triggered during conversion of string: '" << v << "'"); - return false; + return true; + } + // is_arithmetic_v + if constexpr (std::is_floating_point_v) + { + // special cases for floating point + if (std::isnan(source_val)) + { + return !is_signaling_nan(source_val); + } + if (std::isinf(source_val)) + { + IOX_LOG(DEBUG, "got infinity"); + return true; + } } - if (errno_cache == EINVAL) + // out of range (upper bound) + if (source_val > std::numeric_limits::max()) { - IOX_LOG(DEBUG, "EINVAL triggered during conversion of string: " << v); + IOX_LOG(DEBUG, + source_val << " is out of range (upper bound), should be less than " + << std::numeric_limits::max()); return false; } - if (errno_cache != 0) + // out of range (lower bound) + if (source_val < std::numeric_limits::lowest()) { - IOX_LOG(DEBUG, "Unexpected errno: " << errno_cache << ". The input string is: " << v); + IOX_LOG(DEBUG, + source_val << " is out of range (lower bound), should be larger than " + << std::numeric_limits::lowest()); return false; } - return true; } -template -inline bool convert::is_within_range(const SourceType& source_val) noexcept +template +inline bool convert::is_signaling_nan(const SourceType& source_val) noexcept { - if constexpr (std::is_arithmetic_v) + static_assert(std::is_floating_point_v, "SourceType must be a floating point type"); + + if (std::isnan(source_val) == false) + { + return false; + } + + if constexpr (std::is_same_v) + { + return false; + } + else { - if constexpr (std::is_floating_point_v) + using UintType = + typename std::conditional::type; + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + UintType in_bit = *reinterpret_cast(&source_val); + + // check is_quiet + if constexpr (std::is_same_v) { - if (source_val == std::numeric_limits::signaling_NaN()) - { - IOX_LOG(DEBUG, "got signaling NaN"); - return false; - } +// the platform use 'is_signaling' instead of 'is_quiet' +#ifdef __hppa + return (in_bit & FLOAT_SIGNALING_NAN_MASK) != 0; +#else + return (in_bit & FLOAT_SIGNALING_NAN_MASK) == 0; +#endif } - - // out of range (upper bound) - if (source_val > std::numeric_limits::max()) + else if constexpr (std::is_same_v) { - IOX_LOG(DEBUG, - source_val << " is out of range (upper bound), should be less than " - << std::numeric_limits::max()); - return false; +// the platform use 'is_signaling' instead of 'is_quiet' +#ifdef __hppa + return (in_bit & DOUBLE_SIGNALING_NAN_MASK) != 0; +#else + return (in_bit & DOUBLE_SIGNALING_NAN_MASK) == 0; +#endif } - - // out of range (lower bound) - if (source_val < std::numeric_limits::lowest()) + else { - IOX_LOG(DEBUG, - source_val << " is out of range (lower bound), should be larger than " - << std::numeric_limits::lowest()); + static_assert(sizeof(SourceType) == sizeof(float) || sizeof(SourceType) == sizeof(double), + "Function not implemented for this floating point size."); return false; } } +} + +inline bool convert::start_with_neg_sign(const char* v) noexcept +{ + if (v == nullptr) + { + return false; + } + + // remove space + while (*v != '\0' && (isspace((unsigned char)*v) != 0)) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ++v; + } + + return (*v == '-'); +} + +inline bool convert::is_valid_errno(decltype(errno) errno_cache, const char* v) noexcept +{ + if (errno_cache == ERANGE) + { + IOX_LOG(DEBUG, "ERANGE triggered during conversion of string: '" << v << "'"); + return false; + } + + if (errno_cache == EINVAL) + { + IOX_LOG(DEBUG, "EINVAL triggered during conversion of string: " << v); + return false; + } + + if (errno_cache != 0) + { + IOX_LOG(DEBUG, "Unexpected errno: " << errno_cache << ". The input string is: " << v); + return false; + } return true; } From d3f692aa3a5be8cf5fb42f4b8ed698308e12da2d Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Sun, 31 Dec 2023 21:40:49 +0800 Subject: [PATCH 31/33] iox-#2055 Replace 'Destination' with 'TargetType' Signed-off-by: Dennis Liu --- iceoryx_hoofs/utility/include/iox/detail/convert.hpp | 4 ++-- iceoryx_hoofs/utility/include/iox/detail/convert.inl | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index 0482eb243b..b26ebb4e08 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -89,8 +89,8 @@ class convert /// @param v the input string in c type /// @return an iox::optional where, if the return value is iox::nullopt, it indicates a failed /// conversion process - template - static iox::optional from_string(const char* v) noexcept; + template + static iox::optional from_string(const char* v) noexcept; private: template diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index b561439a2c..50fd170dbb 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -59,12 +59,12 @@ convert::toString(const Source& t) noexcept return t; } -template -inline iox::optional convert::from_string(const char* v) noexcept +template +inline iox::optional convert::from_string(const char* v) noexcept { - if constexpr (is_iox_string::value) + if constexpr (is_iox_string::value) { - using IoxString = Destination; + using IoxString = TargetType; if (strlen(v) > IoxString::capacity()) { return iox::nullopt; @@ -73,7 +73,7 @@ inline iox::optional convert::from_string(const char* v) noexcept } else { - static_assert(always_false_v, + static_assert(always_false_v, "For a conversion to 'std::string' please include 'iox/std_string_support.hpp'!\nConversion not " "supported!"); } From a24be4a3385f654efc56af1d835d07152ee77b56 Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Sun, 31 Dec 2023 22:15:34 +0800 Subject: [PATCH 32/33] iox-#2055 Remove 'is_signaling_nan' and 'errno = 0' Signed-off-by: Dennis Liu --- .../utility/include/iox/detail/convert.hpp | 3 - .../utility/include/iox/detail/convert.inl | 72 +------------------ 2 files changed, 1 insertion(+), 74 deletions(-) diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp index b26ebb4e08..e1968c6e14 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.hpp +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.hpp @@ -108,9 +108,6 @@ class convert template static bool is_within_range(const SourceType& source_val) noexcept; - template - static bool is_signaling_nan(const SourceType& source_val) noexcept; - static bool is_valid_errno(decltype(errno) errno_cache, const char* v) noexcept; static bool start_with_neg_sign(const char* v) noexcept; }; diff --git a/iceoryx_hoofs/utility/include/iox/detail/convert.inl b/iceoryx_hoofs/utility/include/iox/detail/convert.inl index 50fd170dbb..b04881c22d 100644 --- a/iceoryx_hoofs/utility/include/iox/detail/convert.inl +++ b/iceoryx_hoofs/utility/include/iox/detail/convert.inl @@ -96,8 +96,6 @@ inline iox::optional convert::from_string(const char* v) noexcept template <> inline iox::optional convert::from_string(const char* v) noexcept { - // we should clean errno first - errno = 0; char* end_ptr = nullptr; if (start_with_neg_sign(v)) @@ -118,7 +116,6 @@ inline iox::optional convert::from_string(const char* v) noexcept template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtof)(v, &end_ptr) @@ -132,7 +129,6 @@ inline iox::optional convert::from_string(const char* v) noexcept template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtod)(v, &end_ptr) @@ -146,7 +142,6 @@ inline iox::optional convert::from_string(const char* v) noexcep template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtold)(v, &end_ptr) @@ -160,7 +155,6 @@ inline iox::optional convert::from_string(const char* template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; if (start_with_neg_sign(v)) @@ -179,7 +173,6 @@ inline iox::optional convert::from_string inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; if (start_with_neg_sign(v)) @@ -198,7 +191,6 @@ inline iox::optional convert::from_string(const ch template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; if (start_with_neg_sign(v)) @@ -218,7 +210,6 @@ inline iox::optional convert::from_string(const char template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; if (start_with_neg_sign(v)) @@ -237,7 +228,6 @@ inline iox::optional convert::from_string(const template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; if (start_with_neg_sign(v)) @@ -256,7 +246,6 @@ inline iox::optional convert::from_string(const ch template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtoll)(v, &end_ptr, STRTOLL_BASE) @@ -270,7 +259,6 @@ inline iox::optional convert::from_string(const char* v) n template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) @@ -284,7 +272,6 @@ inline iox::optional convert::from_string(const char* v) noexcept template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; // use alwaysSuccess for the conversion edge cases in 32-bit system? @@ -299,7 +286,6 @@ inline iox::optional convert::from_string(const char* v) noexcept template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) @@ -313,7 +299,6 @@ inline iox::optional convert::from_string(const char* v) noexcept template <> inline iox::optional convert::from_string(const char* v) noexcept { - errno = 0; char* end_ptr = nullptr; auto call = IOX_POSIX_CALL(strtol)(v, &end_ptr, STRTOL_BASE) @@ -382,13 +367,8 @@ inline bool convert::is_within_range(const SourceType& source_val) noexcept if constexpr (std::is_floating_point_v) { // special cases for floating point - if (std::isnan(source_val)) + if (std::isnan(source_val) || std::isinf(source_val)) { - return !is_signaling_nan(source_val); - } - if (std::isinf(source_val)) - { - IOX_LOG(DEBUG, "got infinity"); return true; } } @@ -413,56 +393,6 @@ inline bool convert::is_within_range(const SourceType& source_val) noexcept return true; } -template -inline bool convert::is_signaling_nan(const SourceType& source_val) noexcept -{ - static_assert(std::is_floating_point_v, "SourceType must be a floating point type"); - - if (std::isnan(source_val) == false) - { - return false; - } - - if constexpr (std::is_same_v) - { - return false; - } - else - { - using UintType = - typename std::conditional::type; - - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - UintType in_bit = *reinterpret_cast(&source_val); - - // check is_quiet - if constexpr (std::is_same_v) - { -// the platform use 'is_signaling' instead of 'is_quiet' -#ifdef __hppa - return (in_bit & FLOAT_SIGNALING_NAN_MASK) != 0; -#else - return (in_bit & FLOAT_SIGNALING_NAN_MASK) == 0; -#endif - } - else if constexpr (std::is_same_v) - { -// the platform use 'is_signaling' instead of 'is_quiet' -#ifdef __hppa - return (in_bit & DOUBLE_SIGNALING_NAN_MASK) != 0; -#else - return (in_bit & DOUBLE_SIGNALING_NAN_MASK) == 0; -#endif - } - else - { - static_assert(sizeof(SourceType) == sizeof(float) || sizeof(SourceType) == sizeof(double), - "Function not implemented for this floating point size."); - return false; - } - } -} - inline bool convert::start_with_neg_sign(const char* v) noexcept { if (v == nullptr) From e02d08bec345089a1a3fce25a27798e323c885bf Mon Sep 17 00:00:00 2001 From: Dennis Liu Date: Sun, 31 Dec 2023 22:21:55 +0800 Subject: [PATCH 33/33] iox-#2055 Simplify underlying type by alias Signed-off-by: Dennis Liu --- iceoryx_posh/source/runtime/ipc_interface_base.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index adea4437fe..c07fb8057c 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -56,13 +56,14 @@ std::string IpcMessageTypeToString(const IpcMessageType msg) noexcept IpcMessageErrorType stringToIpcMessageErrorType(const char* str) noexcept { - std::underlying_type::type msg; - auto result = convert::from_string::type>(str); + using UnderlyingType = std::underlying_type::type; + UnderlyingType msg; + auto result = convert::from_string(str); msg = result.value(); - if (static_cast::type>(IpcMessageErrorType::BEGIN) >= msg - || static_cast::type>(IpcMessageErrorType::END) <= msg) + if (static_cast(IpcMessageErrorType::BEGIN) >= msg + || static_cast(IpcMessageErrorType::END) <= msg) { return IpcMessageErrorType::NOTYPE; } @@ -72,7 +73,8 @@ IpcMessageErrorType stringToIpcMessageErrorType(const char* str) noexcept std::string IpcMessageErrorTypeToString(const IpcMessageErrorType msg) noexcept { - return convert::toString(static_cast::type>(msg)); + using UnderlyingType = std::underlying_type::type; + return convert::toString(static_cast(msg)); } template