Skip to content

Commit

Permalink
Merge pull request #993 from ApexAI/iox-#992-create-templated-from-an…
Browse files Browse the repository at this point in the history
…d-into-free-functions-for-conversion

iox-#992 Add templated from/into free functions for conversions
  • Loading branch information
elBoberido authored Jan 10, 2022
2 parents 76ba504 + 3f11e2f commit 10a5506
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:**

Expand Down
60 changes: 59 additions & 1 deletion iceoryx_hoofs/include/iceoryx_hoofs/cxx/helplets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
#ifndef IOX_HOOFS_CXX_HELPLETS_HPP
#define IOX_HOOFS_CXX_HELPLETS_HPP

#include <assert.h>
#include "iceoryx_hoofs/cxx/type_traits.hpp"

#include <cassert>
#include <cstdint>
#include <cstring>
#include <iostream>
Expand Down Expand Up @@ -277,6 +279,62 @@ bool isValidFileName(const string<StringCapacity>& name) noexcept;
template <uint64_t StringCapacity>
bool isValidFilePath(const string<StringCapacity>& 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, HighLevel>(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 <typename F, typename T>
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<Bar>(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 <typename T, typename F>
constexpr T into(const F value) noexcept;

} // namespace cxx
} // namespace iox

Expand Down
1 change: 1 addition & 0 deletions iceoryx_hoofs/include/iceoryx_hoofs/cxx/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef IOX_HOOFS_CXX_STRING_HPP
#define IOX_HOOFS_CXX_STRING_HPP

#include "iceoryx_hoofs/cxx/type_traits.hpp"
#include "iceoryx_hoofs/internal/cxx/string_internal.hpp"
#include "optional.hpp"

Expand Down
9 changes: 9 additions & 0 deletions iceoryx_hoofs/include/iceoryx_hoofs/cxx/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ struct add_const_conditionally<T, const C>
template <typename T, typename C>
using add_const_conditionally_t = typename add_const_conditionally<T, C>::type;

///
/// @brief Helper value to bind a static_assert to a type
/// @code
/// static_assert(always_false_v<Foo>, "Not implemented for the given type!");
/// @endcode
///
template <typename>
constexpr bool always_false_v = false;

///
/// @brief Verifies whether the passed Callable type is in fact invocable with the given arguments
///
Expand Down
13 changes: 13 additions & 0 deletions iceoryx_hoofs/include/iceoryx_hoofs/internal/cxx/helplets.inl
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,19 @@ inline bool isValidFilePath(const string<StringCapacity>& name) noexcept

return false;
}

template <typename F, typename T>
constexpr T from(const F) noexcept
{
static_assert(always_false_v<F> && always_false_v<T>, "Conversion for the specified types is not implemented!\
Please specialize `template <typename F, typename T> constexpr T from(const F) noexcept`!");
}

template <typename T, typename F>
constexpr T into(const F e) noexcept
{
return from<F, T>(e);
}
} // namespace cxx
} // namespace iox

Expand Down
20 changes: 6 additions & 14 deletions iceoryx_hoofs/include/iceoryx_hoofs/internal/cxx/string.inl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
// Copyright (c) 2021 - 2022 by Apex.AI Inc. 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.
Expand Down Expand Up @@ -362,18 +362,10 @@ inline std::ostream& operator<<(std::ostream& stream, const string<Capacity>& st
return stream;
}

/// @brief struct used to disable the equality operators for fixed string and char pointer; it is needed, because a
/// simple false will be evaluated before the template is instanciated and therefore the program won't be compiled
template <uint64_t>
struct always_false
{
static constexpr bool value = false;
};

template <uint64_t Capacity>
inline bool string<Capacity>::operator==(const char* const) const noexcept
{
static_assert(always_false<Capacity>::value,
static_assert(cxx::always_false_v<string<Capacity>>,
"The equality operator for fixed string and char pointer is disabled, because it may lead to "
"undefined behavior if the char array is not null-terminated. Please convert the char array to a "
"fixed string with string(TruncateToCapacity_t, const char* const other, const uint64_t count) "
Expand All @@ -384,7 +376,7 @@ inline bool string<Capacity>::operator==(const char* const) const noexcept
template <uint64_t Capacity>
inline bool string<Capacity>::operator!=(const char* const) const noexcept
{
static_assert(always_false<Capacity>::value,
static_assert(cxx::always_false_v<string<Capacity>>,
"The inequality operator for fixed string and char pointer is disabled, because it may lead to "
"undefined behavior if the char array is not null-terminated. Please convert the char array to a "
"fixed string with string(TruncateToCapacity_t, const char* const other, const uint64_t count) "
Expand All @@ -395,7 +387,7 @@ inline bool string<Capacity>::operator!=(const char* const) const noexcept
template <uint64_t Capacity>
inline bool operator==(const char* const, const string<Capacity>&) noexcept
{
static_assert(always_false<Capacity>::value,
static_assert(cxx::always_false_v<string<Capacity>>,
"The equality operator for char pointer and fixed string is disabled, because it may lead to "
"undefined behavior if the char array is not null-terminated. Please convert the char array to a "
"fixed string with string(TruncateToCapacity_t, const char* const other, const uint64_t count) "
Expand All @@ -406,7 +398,7 @@ inline bool operator==(const char* const, const string<Capacity>&) noexcept
template <uint64_t Capacity>
inline bool operator!=(const char* const, const string<Capacity>&) noexcept
{
static_assert(always_false<Capacity>::value,
static_assert(cxx::always_false_v<string<Capacity>>,
"The inequality operator for char pointer and fixed string is disabled, because it may lead to "
"undefined behavior if the char array is not null-terminated. Please convert the char array to a "
"fixed string with string(TruncateToCapacity_t, const char* const other, const uint64_t count) "
Expand All @@ -418,7 +410,7 @@ template <uint64_t Capacity>
template <typename T>
inline string<Capacity>& string<Capacity>::operator+=(const T&) noexcept
{
static_assert(always_false<Capacity>::value,
static_assert(cxx::always_false_v<string<Capacity>>,
"operator += is not supported by cxx::string, please use append or unsafe_append instead");
return *this;
}
Expand Down
51 changes: 50 additions & 1 deletion iceoryx_hoofs/test/moduletests/test_cxx_helplets.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex AI Inc. All rights reserved.
// Copyright (c) 2021 - 2022 by Apex AI Inc. 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.
Expand All @@ -23,6 +23,40 @@
#include <string>
#include <type_traits>

namespace
{
enum class A
{
A1 = 13,
A2
};

enum class B
{
B1 = 42,
B2
};
} // namespace

namespace iox
{
namespace cxx
{
template <>
constexpr B from<A, B>(A e) noexcept
{
switch (e)
{
case A::A1:
return B::B1;
case A::A2:
return B::B2;
}
}

} // namespace cxx
} // namespace iox

namespace
{
using namespace ::testing;
Expand Down Expand Up @@ -449,5 +483,20 @@ TEST(Helplets_test_isValidFilePath, EmptyFilePathIsInvalid)
EXPECT_FALSE(isValidFilePath(string<FILE_PATH_LENGTH>("")));
}

TEST(Helplets_test_from, fromWorksAsConstexpr)
{
constexpr A FROM_VALUE{A::A1};
constexpr B TO_VALUE{B::B1};
constexpr B SUT = iox::cxx::from<A, B>(FROM_VALUE);
EXPECT_EQ(SUT, TO_VALUE);
}

TEST(Helplets_test_into, intoWorksWhenFromIsSpecialized)
{
constexpr A FROM_VALUE{A::A2};
constexpr B TO_VALUE{B::B2};
constexpr B SUT = iox::cxx::into<B>(FROM_VALUE);
EXPECT_EQ(SUT, TO_VALUE);
}

} // namespace
8 changes: 8 additions & 0 deletions iceoryx_hoofs/test/moduletests/test_cxx_type_traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ TEST(TypeTraitsTest, AddConstConditionallyTypeAliasWorks)
EXPECT_TRUE(std::is_const<SutTypeResult>::value);
}

TEST(TypeTraitsTest, AlwaysFalseWorks)
{
struct Foo
{
};
EXPECT_FALSE(always_false_v<Foo>);
}

TEST(TypeTraitsTest, IsFunctionPointerResolvesToTrue)
{
auto result = is_function_pointer<void (*)(double)>::value;
Expand Down

0 comments on commit 10a5506

Please sign in to comment.