diff --git a/CHANGELOG.md b/CHANGELOG.md index f8bc538f1e..3c4e938284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Axivion analysis on CI[\#409](https://github.com/eclipse-iceoryx/iceoryx/issues/409) - Cpptoml can be provided by an external source[\#951](https://github.com/eclipse-iceoryx/iceoryx/issues/) - Extend cxx::optional constructor for in place construction so that copy/move for values inside the optional even could be deleted[\#967](https://github.com/eclipse-iceoryx/iceoryx/issues/967) +- Add templated `from`/`into` free functions to formalize conversions from enums and other types [#992](https://github.com/eclipse-iceoryx/iceoryx/issues/992) **Bugfixes:** diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/cxx/helplets.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/cxx/helplets.hpp index bc91d1d372..56876a2466 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/cxx/helplets.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/cxx/helplets.hpp @@ -17,7 +17,9 @@ #ifndef IOX_HOOFS_CXX_HELPLETS_HPP #define IOX_HOOFS_CXX_HELPLETS_HPP -#include +#include "iceoryx_hoofs/cxx/type_traits.hpp" + +#include #include #include #include @@ -277,6 +279,62 @@ bool isValidFileName(const string& name) noexcept; template bool isValidFilePath(const string& name) noexcept; +/// @brief Converts a value of type F to a corresponding value of type T. This function needs to be specialized by the +/// user for the types to be converted. +/// @code +/// enum class LowLevel +/// { +/// FileDescriptorInvalid, +/// FileDescriptorCorrupt, +/// Timeout +/// }; +/// +/// enum class HighLevel +/// { +/// FileDescriptorError, +/// Timeout +/// }; +/// +/// namespace iox +/// { +/// namespace cxx +/// { +/// template <> +/// constexpr HighLevel from(LowLevel e) noexcept +/// { +/// switch (e) +/// { +/// case LowLevel::FileDescriptorCorrupt: +/// return HighLevel::FileDescriptorError; +/// case LowLevel::FileDescriptorInvalid: +/// return HighLevel::FileDescriptorError; +/// case LowLevel::Timeout: +/// return HighLevel::Timeout; +/// } +/// } +/// } // namespace cxx +/// } // namespace iox +/// @endcode +/// @tparam F is the 'from' type +/// @tparam T is the 'to' type +/// @param[in] value of type F to convert to T +/// @return converted value of F to corresponding value of T +template +constexpr T from(const F value) noexcept; + +/// @brief Converts a value of type F to a corresponding value of type T. This is a convenience function which is +/// automatically available when `from` is implemented. This function shall therefore not be specialized but always the +/// `from` function. +/// @code +/// Bar b = iox::cxx::into(Foo::ENUM_VALUE); +/// @endcode +/// @tparam T is the 'to' type +/// @tparam F is the 'from' type +/// @param[in] value of type F to convert to T +/// @return converted value of F to corresponding value of T +template +constexpr T into(const F value) noexcept; + } // namespace cxx } // namespace iox diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/cxx/type_traits.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/cxx/type_traits.hpp index 345f171a47..3199a9c437 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/cxx/type_traits.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/cxx/type_traits.hpp @@ -45,6 +45,15 @@ struct add_const_conditionally template using add_const_conditionally_t = typename add_const_conditionally::type; +/// +/// @brief Helper value to bind a static_assert to a type +/// @code +/// static_assert(always_false_v, "Not implemented for the given type!"); +/// @endcode +/// +template +constexpr bool always_false_v = false; + /// /// @brief Verifies whether the passed Callable type is in fact invocable with the given arguments /// diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/internal/cxx/helplets.inl b/iceoryx_hoofs/include/iceoryx_hoofs/internal/cxx/helplets.inl index 0888ff9cf5..15d0dd1321 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/internal/cxx/helplets.inl +++ b/iceoryx_hoofs/include/iceoryx_hoofs/internal/cxx/helplets.inl @@ -126,6 +126,19 @@ inline bool isValidFilePath(const string& name) noexcept return false; } + +template +constexpr T from(const F) noexcept +{ + static_assert(always_false_v && always_false_v, "Conversion for the specified types is not implemented!\ + Please specialize `template constexpr T from(const F) noexcept`!"); +} + +template +constexpr T into(const F e) noexcept +{ + return from(e); +} } // namespace cxx } // namespace iox diff --git a/iceoryx_hoofs/test/moduletests/test_cxx_helplets.cpp b/iceoryx_hoofs/test/moduletests/test_cxx_helplets.cpp index 60da7f60dd..78ebd534af 100644 --- a/iceoryx_hoofs/test/moduletests/test_cxx_helplets.cpp +++ b/iceoryx_hoofs/test/moduletests/test_cxx_helplets.cpp @@ -23,6 +23,40 @@ #include #include +namespace +{ +enum A +{ + A1 = 13, + A2 +}; + +enum B +{ + B1 = 42, + B2 +}; +} // namespace + +namespace iox +{ +namespace cxx +{ +template <> +constexpr B from(A e) noexcept +{ + switch (e) + { + case A1: + return B1; + case A2: + return B2; + } +} + +} // namespace cxx +} // namespace iox + namespace { using namespace ::testing; @@ -449,5 +483,20 @@ TEST(Helplets_test_isValidFilePath, EmptyFilePathIsInvalid) EXPECT_FALSE(isValidFilePath(string(""))); } +TEST(Helplets_test_from, fromWorksAsConstexpr) +{ + constexpr A FROM_VALUE{A1}; + constexpr B TO_VALUE{B1}; + constexpr B SUT = iox::cxx::from(FROM_VALUE); + EXPECT_EQ(SUT, TO_VALUE); +} + +TEST(Helplets_test_into, intoWorksWhenFromIsSpecialized) +{ + constexpr A FROM_VALUE{A2}; + constexpr B TO_VALUE{B2}; + constexpr B SUT = iox::cxx::into(FROM_VALUE); + EXPECT_EQ(SUT, TO_VALUE); +} } // namespace diff --git a/iceoryx_hoofs/test/moduletests/test_cxx_type_traits.cpp b/iceoryx_hoofs/test/moduletests/test_cxx_type_traits.cpp index 9f257b83b4..a6e0f71af6 100644 --- a/iceoryx_hoofs/test/moduletests/test_cxx_type_traits.cpp +++ b/iceoryx_hoofs/test/moduletests/test_cxx_type_traits.cpp @@ -126,6 +126,14 @@ TEST(TypeTraitsTest, AddConstConditionallyTypeAliasWorks) EXPECT_TRUE(std::is_const::value); } +TEST(TypeTraitsTest, AlwaysFalseWorks) +{ + struct Foo + { + }; + EXPECT_FALSE(always_false_v); +} + TEST(TypeTraitsTest, IsFunctionPointerResolvesToTrue) { auto result = is_function_pointer::value;