From d53b0fc5362adc61687a6d61836fa43b599b5327 Mon Sep 17 00:00:00 2001 From: jparisu Date: Wed, 24 Aug 2022 11:23:10 +0200 Subject: [PATCH 1/8] Refactor and addition to macros Signed-off-by: jparisu --- .../macros/custom_enumeration.hpp | 147 ++++++++++ .../ddsrouter_utils/{ => macros}/macros.hpp | 41 ++- .../macros/recursive_macros.hpp | 115 ++++++++ ddsrouter_utils/test/unittest/CMakeLists.txt | 2 + .../test/unittest/macros/CMakeLists.txt | 105 ++++++++ .../macros/enumerationBuilderMacrosTest.cpp | 253 ++++++++++++++++++ .../test/unittest/macros/macrosTest.cpp | 66 +++++ .../unittest/macros/recursiveMacrosTest.cpp | 128 +++++++++ 8 files changed, 853 insertions(+), 4 deletions(-) create mode 100644 ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp rename ddsrouter_utils/include/ddsrouter_utils/{ => macros}/macros.hpp (54%) create mode 100644 ddsrouter_utils/include/ddsrouter_utils/macros/recursive_macros.hpp create mode 100644 ddsrouter_utils/test/unittest/macros/CMakeLists.txt create mode 100644 ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp create mode 100644 ddsrouter_utils/test/unittest/macros/macrosTest.cpp create mode 100644 ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp diff --git a/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp b/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp new file mode 100644 index 000000000..4c8b18744 --- /dev/null +++ b/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp @@ -0,0 +1,147 @@ +// Copyright 2021 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file macros.hpp + * + * This file contains constant values common for the whole project + */ + +#ifndef _DDSROUTERUTILS_MACROS_CUSTOMENUMERATION_HPP_ +#define _DDSROUTERUTILS_MACROS_CUSTOMENUMERATION_HPP_ + +#include +#include + +#include +#include +#include + +namespace eprosima { +namespace ddsrouter { +namespace utils { + +/** + * @brief This macro creates a Custom Enumeration + * + * A Custom Enumeration is an Enumeration class that internally has a enum class and has several methods to interact + * with it: + * - creation from enum value + * - creation from string + * - conversion to string + * - conversion to int + * + * @warning Requires a ";" after call + */ + +// #define ENUMERATION_BUILDER(enumeration_name, ...) \ +// \ +// class enumeration_name \ +// { \ +// public: \ +// \ +// /* Internal enumeration */ \ +// enum class Enum {__VA_ARGS__}; \ +// \ +// /* Constructor from Enumeration */ \ +// enumeration_name(Enum e) : internal_value_(e) {} \ +// \ +// /* Constructor from string */ \ +// enumeration_name(const std::string& s) : internal_value_(from_string_(s)) {} \ +// \ +// /* To string method */ \ +// std::string to_string() const { return names_[static_cast(internal_value_)]; } \ +// \ +// /* To string operator */ \ +// operator std::string() const { return this->to_string(); } \ +// \ +// /* To int operator */ \ +// operator int() const { return static_cast(internal_value_); } \ +// \ +// /* To Enum operator */ \ +// operator Enum() const { return internal_value_; } \ +// \ +// /* Equal comparision */ \ +// bool operator== (const enumeration_name& other) { return this->internal_value_ == other.internal_value_; } \ +// \ +// /* Equal comparision */ \ +// bool operator== (const Enum& other) { return this->internal_value_ == other; } \ +// \ +// /* Not Equal comparision */ \ +// bool operator!= (const enumeration_name& other) { return this->internal_value_ != other.internal_value_; } \ +// \ +// /* Not Equal comparision */ \ +// bool operator!= (const Enum& other) { return this->internal_value_ != other; } \ +// \ +// protected: \ +// \ +// /* From string */ \ +// static Enum from_string_ (const std::string& s) \ +// { \ +// for (int i=0; i(i); \ +// throw eprosima::ddsrouter::utils::InitializationException( \ +// STR_ENTRY << "Not correct name " << s << " for Enum " << STRINGIFY(enumeration_name) << "."); \ +// } \ +// \ +// \ +// /* Names array */ \ +// static const std::array names_; \ +// \ +// /* Internal value */ \ +// Enum internal_value_; \ +// \ +// }; \ +// \ +// /* Serialization operation */ \ +// std::ostream& operator <<(std::ostream& os, const enumeration_name& e) { os << e.to_string(); return os; } \ +// \ +// /* Initialize name arrays */ \ +// const std::array enumeration_name::names_ = \ +// { APPLY_MACRO_FOR_EACH(STRINGIFY_WITH_COMMA, __VA_ARGS__) } + + + + +#define ENUMERATION_BUILDER(enumeration_name, ...) \ + \ + /* Declare enumeration */ \ + enum class enumeration_name {__VA_ARGS__}; \ + \ + /* Initialize name arrays */ \ + const std::array names_##enumeration_name = \ + { APPLY_MACRO_FOR_EACH(STRINGIFY_WITH_COMMA, __VA_ARGS__) }; \ + \ + /* To string method */ \ + const std::string& to_string(const enumeration_name& e) \ + { return names_##enumeration_name[static_cast(e)]; } \ + \ + /* From string */ \ + enumeration_name from_string_##enumeration_name(const std::string& s) \ + { \ + for (int i=0; i(i); \ + throw eprosima::ddsrouter::utils::InitializationException( \ + STR_ENTRY << "Not correct name " << s << " for Enum " << STRINGIFY(enumeration_name) << "."); \ + } \ + \ + /* Serialization operation */ \ + std::ostream& operator <<(std::ostream& os, const enumeration_name& e) { os << to_string(e); return os; } + + +} /* namespace utils */ +} /* namespace ddsrouter */ +} /* namespace eprosima */ + +#endif /* _DDSROUTERUTILS_MACROS_CUSTOMENUMERATION_HPP_ */ diff --git a/ddsrouter_utils/include/ddsrouter_utils/macros.hpp b/ddsrouter_utils/include/ddsrouter_utils/macros/macros.hpp similarity index 54% rename from ddsrouter_utils/include/ddsrouter_utils/macros.hpp rename to ddsrouter_utils/include/ddsrouter_utils/macros/macros.hpp index 3dc80494d..98ced0c49 100644 --- a/ddsrouter_utils/include/ddsrouter_utils/macros.hpp +++ b/ddsrouter_utils/include/ddsrouter_utils/macros/macros.hpp @@ -18,8 +18,8 @@ * This file contains constant values common for the whole project */ -#ifndef _DDSROUTERUTILS_MACROS_HPP_ -#define _DDSROUTERUTILS_MACROS_HPP_ +#ifndef _DDSROUTERUTILS_MACROS_MACROS_HPP_ +#define _DDSROUTERUTILS_MACROS_MACROS_HPP_ #include @@ -27,16 +27,49 @@ namespace eprosima { namespace ddsrouter { namespace utils { +///////////////////////// +// FORMAT +///////////////////////// + +/** + * @brief Get string of the argument passed to the macro + * + * @example + * STRINGIFY(value) = "value" + */ #define STRINGIFY(x) #x +//! Same as \c STRINGIFY but adding a comma "," at the end +#define STRINGIFY_WITH_COMMA(x) #x, + + +///////////////////////// +// TYPES +///////////////////////// + +/** + * @brief Force the specialization type of a template to be a subclass of a Class. + * + * @example + * FORCE_TEMPLATE_SUBCLASS(A, B) = static assert <=> B not inherit from A + * + * @param base parent class that \c derived must inherit. + * @param derived specialization class. + */ #define FORCE_TEMPLATE_SUBCLASS(base, derived) \ static_assert(std::is_base_of::value, STRINGIFY(derived) " class not derived from " STRINGIFY(base)) -// TODO: probably in the future is needed to create a utils method that transforms this name to a human reasonable name +/** + * @brief Get string of the name of the CPP Data Type of the argument + * + * @example + * STRINGIFY(int) = "j" + * STRINGIFY(string) = "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE" + */ #define TYPE_NAME(x) typeid(x).name() } /* namespace utils */ } /* namespace ddsrouter */ } /* namespace eprosima */ -#endif /* _DDSROUTERUTILS_MACROS_HPP_ */ +#endif /* _DDSROUTERUTILS_MACROS_MACROS_HPP_ */ diff --git a/ddsrouter_utils/include/ddsrouter_utils/macros/recursive_macros.hpp b/ddsrouter_utils/include/ddsrouter_utils/macros/recursive_macros.hpp new file mode 100644 index 000000000..603211543 --- /dev/null +++ b/ddsrouter_utils/include/ddsrouter_utils/macros/recursive_macros.hpp @@ -0,0 +1,115 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file recursive_macros.hpp + * + * This file contains constant values common for the whole project + */ + +#ifndef _DDSROUTERUTILS_MACROS_RECURSIVEMACROS_HPP_ +#define _DDSROUTERUTILS_MACROS_RECURSIVEMACROS_HPP_ + +#include + +namespace eprosima { +namespace ddsrouter { +namespace utils { + +///////////////////////// +// COUNT ARGUMENTS +///////////////////////// + +/** + * @brief Get 11th macro. + * + * @note This macro is used in \c COUNT_ARGUMENT macro. + */ +#define _ELEVENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, ...) \ + a11 + +/** + * @brief Count number of arguments in a variadic macro with maximum 9 variables + * + * @note This is an auxiliary macro that encapsulates the funtionality of \c COUNT_ARGUMENTS so that macro + * could be changed to a higher value without breaking API. + * + * @note \c dummy value is required to non argument calls. + */ +#define _COUNT_ARGUMENTS__UP_TO_NINE(...) \ + _ELEVENTH_ARGUMENT(dummy, ## __VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +/** + * @brief Count number of arguments in a variadic macro + * + * @warning This macro only allows up to 9 values. + * + * @note if more arguments required, change \c _ELEVENTH_ARGUMENT for a higher one. + * + * @example + * COUNT_ARGUMENTS(el1, el2, el3) = 3 + */ +#define COUNT_ARGUMENTS(...) \ + _COUNT_ARGUMENTS__UP_TO_NINE(__VA_ARGS__) + + +///////////////////////// +// FOR EACH +///////////////////////// + +/** + * @brief These macros allow to create an iterative APPLY_MACRO_FOR_EACH loop over every argument. + * + * Each item of form \c _FE_N allow to evaluate the function \c ACTION for the next \c N arguments. + */ +#define _FE_1(ACTION, X) ACTION(X) +#define _FE_2(ACTION, X, ...) ACTION(X) _FE_1(ACTION, __VA_ARGS__) +#define _FE_3(ACTION, X, ...) ACTION(X) _FE_2(ACTION, __VA_ARGS__) +#define _FE_4(ACTION, X, ...) ACTION(X) _FE_3(ACTION, __VA_ARGS__) +#define _FE_5(ACTION, X, ...) ACTION(X) _FE_4(ACTION, __VA_ARGS__) +#define _FE_6(ACTION, X, ...) ACTION(X) _FE_5(ACTION, __VA_ARGS__) +#define _FE_7(ACTION, X, ...) ACTION(X) _FE_6(ACTION, __VA_ARGS__) +#define _FE_8(ACTION, X, ...) ACTION(X) _FE_7(ACTION, __VA_ARGS__) +#define _FE_9(ACTION, X, ...) ACTION(X) _FE_8(ACTION, __VA_ARGS__) +//... repeat as needed + +/** + * @brief Get the 9th argument + * + * @note this is useful for \c APPLY_MACRO_FOR_EACH macro. + */ +#define _GET_NINTH_ARGUMENT(_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) \ + NAME + +#define _APPLY_MACRO_FOR_EACH__UP_TO_NINE(action,...) \ + _GET_NINTH_ARGUMENT(__VA_ARGS__,_FE_9,_FE_8,_FE_7,_FE_6,_FE_5,_FE_4,_FE_3,_FE_2,_FE_1)(action,__VA_ARGS__) + +/** + * @brief Execute \c action (must be a macro) for every argument after it. + * + * @warning This macro only allows up to 9 values. + * + * @note if more arguments required, change \c _APPLY_MACRO_FOR_EACH__UP_TO_NINE for a higher one. + * + * @example + * APPLY_MACRO_FOR_EACH(print, el1, el2, el3) => print(el1); print(el2); print(el3); + */ +#define APPLY_MACRO_FOR_EACH(action,...) \ + _APPLY_MACRO_FOR_EACH__UP_TO_NINE(action,__VA_ARGS__) + +} /* namespace utils */ +} /* namespace ddsrouter */ +} /* namespace eprosima */ + +#endif /* _DDSROUTERUTILS_MACROS_RECURSIVEMACROS_HPP_ */ diff --git a/ddsrouter_utils/test/unittest/CMakeLists.txt b/ddsrouter_utils/test/unittest/CMakeLists.txt index abf50752f..30b0e8939 100644 --- a/ddsrouter_utils/test/unittest/CMakeLists.txt +++ b/ddsrouter_utils/test/unittest/CMakeLists.txt @@ -15,10 +15,12 @@ # Add test subdirectories add_subdirectory(event) add_subdirectory(exception) +add_subdirectory(macros) add_subdirectory(math) add_subdirectory(memory) add_subdirectory(return_code) add_subdirectory(thread_pool) add_subdirectory(time) +add_subdirectory(types) add_subdirectory(utils) add_subdirectory(wait) diff --git a/ddsrouter_utils/test/unittest/macros/CMakeLists.txt b/ddsrouter_utils/test/unittest/macros/CMakeLists.txt new file mode 100644 index 000000000..6395249a0 --- /dev/null +++ b/ddsrouter_utils/test/unittest/macros/CMakeLists.txt @@ -0,0 +1,105 @@ +# Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +##################################### +# STD MACROS TEST +##################################### + +set(TEST_NAME macrosTest) + +set(TEST_SOURCES + macrosTest.cpp + ) + +set(TEST_LIST + stringify + ) + +set(TEST_EXTRA_LIBRARIES + ) + +set(TEST_NEEDED_SOURCES + ) + +add_unittest_executable( + "${TEST_NAME}" + "${TEST_SOURCES}" + "${TEST_LIST}" + "${TEST_EXTRA_LIBRARIES}" + "${TEST_NEEDED_SOURCES}" + ) + +##################################### +# RECURSIVE MACROS TEST +##################################### + +set(TEST_NAME recursiveMacrosTest) + +set(TEST_SOURCES + recursiveMacrosTest.cpp + ) + +set(TEST_LIST + count_arguments + apply_APPLY_MACRO_FOR_EACH + ) + +set(TEST_EXTRA_LIBRARIES + ) + +set(TEST_NEEDED_SOURCES + ) + +add_unittest_executable( + "${TEST_NAME}" + "${TEST_SOURCES}" + "${TEST_LIST}" + "${TEST_EXTRA_LIBRARIES}" + "${TEST_NEEDED_SOURCES}" + ) + +##################################### +# ENUMERATION BUILDER TEST +##################################### + +set(TEST_NAME enumerationBuilderMacrosTest) + +set(TEST_SOURCES + enumerationBuilderMacrosTest.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/Formatter.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/exception/Exception.cpp + ) + +set(TEST_LIST + construct_enum + construct_string + to_string + string_operator + int_operator + serializator + ) + +set(TEST_EXTRA_LIBRARIES + ) + +set(TEST_NEEDED_SOURCES + ) + +add_unittest_executable( + "${TEST_NAME}" + "${TEST_SOURCES}" + "${TEST_LIST}" + "${TEST_EXTRA_LIBRARIES}" + "${TEST_NEEDED_SOURCES}" + ) diff --git a/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp b/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp new file mode 100644 index 000000000..a2d44bbe7 --- /dev/null +++ b/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp @@ -0,0 +1,253 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +#include + +// namespace test { + +// ENUMERATION_BUILDER( +// TestCustomEnum, +// el0, +// el1, +// other_element, +// noElement_atAll_00 +// ); + +// constexpr unsigned int NUMBER_OF_ELEMENTS = 4; + +// const std::array enum_values = +// { +// TestCustomEnum::Enum::el0, +// TestCustomEnum::Enum::el1, +// TestCustomEnum::Enum::other_element, +// TestCustomEnum::Enum::noElement_atAll_00, +// }; + +// const std::array class_values = +// { +// TestCustomEnum(TestCustomEnum::Enum::el0), +// TestCustomEnum(TestCustomEnum::Enum::el1), +// TestCustomEnum(TestCustomEnum::Enum::other_element), +// TestCustomEnum(TestCustomEnum::Enum::noElement_atAll_00), +// }; + +// const std::array string_values = +// { +// "el0", +// "el1", +// "other_element", +// "noElement_atAll_00", +// }; + +// } /* namespace test */ + +// /** +// * Construct enumeration of type TestCustomEnum from its values. +// * +// * CASES: +// * x each element inside +// */ +// TEST(enumerationBuilderMacrosTest, construct_enum) +// { +// // x each element inside +// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) +// { +// test::TestCustomEnum value(test::enum_values[i]); +// ASSERT_TRUE(value == test::class_values[i]); +// ASSERT_TRUE(value == test::enum_values[i]); +// } +// } + +// /** +// * Construct enumeration of type TestCustomEnum from a string. +// * +// * CASES: +// * x each element inside +// * - string not in enumeration +// */ +// TEST(enumerationBuilderMacrosTest, construct_string) +// { +// // x each element inside +// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) +// { +// test::TestCustomEnum value(test::string_values[i]); +// ASSERT_TRUE(value == test::class_values[i]); +// ASSERT_TRUE(value == test::enum_values[i]); +// } + +// // string not in enumeration +// ASSERT_THROW(test::TestCustomEnum("noElement_atAll_0") , eprosima::ddsrouter::utils::InitializationException); +// } + +// /** +// * Compare to_string with expected result +// * +// * CASES: +// * x each element inside +// */ +// TEST(enumerationBuilderMacrosTest, to_string) +// { +// // x each element inside +// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) +// { +// ASSERT_EQ(test::class_values[i].to_string(), test::string_values[i]); +// } +// } + +// /** +// * Compare to string cast operator with expected result +// * +// * CASES: +// * x each element inside +// */ +// TEST(enumerationBuilderMacrosTest, string_operator) +// { +// // x each element inside +// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) +// { +// ASSERT_EQ(static_cast(test::class_values[i]), test::string_values[i]); +// } +// } + +// /** +// * Compare to int cast operator with expected result +// * +// * CASES: +// * x each element inside +// */ +// TEST(enumerationBuilderMacrosTest, int_operator) +// { +// // x each element inside +// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) +// { +// ASSERT_EQ(static_cast(test::class_values[i]), i); +// } +// } + +// /** +// * Compare to int cast operator with expected result +// * +// * CASES: +// * x each element inside +// */ +// TEST(enumerationBuilderMacrosTest, serializator) +// { +// // x each element inside +// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) +// { +// std::stringstream ss; +// ss << test::class_values[i]; +// ASSERT_EQ(ss.str(), test::string_values[i]); +// } +// } + +namespace test { + +ENUMERATION_BUILDER( + TestCustomEnum, + el0, + el1, + other_element, + noElement_atAll_00 +); + +ENUMERATION_BUILDER( + TestCustomOtherEnum, + el_0, +); + +constexpr unsigned int NUMBER_OF_ELEMENTS = 4; + +const std::array enum_values = +{ + TestCustomEnum::el0, + TestCustomEnum::el1, + TestCustomEnum::other_element, + TestCustomEnum::noElement_atAll_00, +}; + +const std::array string_values = +{ + "el0", + "el1", + "other_element", + "noElement_atAll_00", +}; + +} /* namespace test */ + +/** + * Construct enumeration of type TestCustomEnum from a string. + * + * CASES: + * x each element inside + * - string not in enumeration + */ +TEST(enumerationBuilderMacrosTest, from_string) +{ + // x each element inside + for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) + { + test::TestCustomEnum value = test::from_string_TestCustomEnum(test::string_values[i]); + ASSERT_TRUE(value == test::enum_values[i]); + } + + // string not in enumeration + ASSERT_THROW(test::from_string_TestCustomEnum("el_0") , eprosima::ddsrouter::utils::InitializationException); +} + +/** + * Compare to_string with expected result + * + * CASES: + * x each element inside + */ +TEST(enumerationBuilderMacrosTest, to_string) +{ + // x each element inside + for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) + { + ASSERT_EQ(test::to_string(test::enum_values[i]), test::string_values[i]); + } +} + +/** + * Compare to int cast operator with expected result + * + * CASES: + * x each element inside + */ +TEST(enumerationBuilderMacrosTest, serializator) +{ + // x each element inside + for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) + { + std::stringstream ss; + ss << test::enum_values[i]; + ASSERT_EQ(ss.str(), test::string_values[i]); + } +} + +int main( + int argc, + char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/ddsrouter_utils/test/unittest/macros/macrosTest.cpp b/ddsrouter_utils/test/unittest/macros/macrosTest.cpp new file mode 100644 index 000000000..e7d80f52b --- /dev/null +++ b/ddsrouter_utils/test/unittest/macros/macrosTest.cpp @@ -0,0 +1,66 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +/** + * Test \c STRINGIFY macro + * + * Cases: + * random string + * variable name + */ +TEST(macrosTest, stringify) +{ + // random string + { + ASSERT_EQ( + std::string(STRINGIFY(abcdefghijkl)), + std::string("abcdefghijkl") + ); + + ASSERT_EQ( + std::string(STRINGIFY(k1)), + std::string("k1") + ); + } + + // variable name + { + // Integer + int _random_value = 0; + ASSERT_EQ( + std::string(STRINGIFY(_random_value)), + std::string("_random_value") + ); + + // String + std::string _random_string = "other value"; + ASSERT_EQ( + std::string(STRINGIFY(_random_string)), + std::string("_random_string") + ); + } +} + +int main( + int argc, + char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp b/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp new file mode 100644 index 000000000..8f7ab083f --- /dev/null +++ b/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp @@ -0,0 +1,128 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include + +/** + * Test \c COUNT_ARGUMENTS macro + * + * Cases: + * 0 + * 1 + * 5 + * 9 + */ +TEST(recursiveMacrosTest, count_arguments) +{ + // 0 + { + ASSERT_EQ( + 0, + COUNT_ARGUMENTS() + ); + } + + // 1 + { + ASSERT_EQ( + 1, + COUNT_ARGUMENTS( + "el1" + ) + ); + } + + // 5 + { + ASSERT_EQ( + 5, + COUNT_ARGUMENTS( + "el1", "el2", "el3", "el4", "el5" + ) + ); + } + + // 9 + { + ASSERT_EQ( + 9, + COUNT_ARGUMENTS( + "el1", "el2", "el3", "el4", "el5", + "el1", "el2", "el3", "el4" + ) + ); + } +} + +/** + * Test \c APPLY_MACRO_FOR_EACH macro + * + * Cases: + * addition + * string concatenation + */ +TEST(recursiveMacrosTest, apply_APPLY_MACRO_FOR_EACH) +{ + +#define APPLY_LAMBDA(x) lambda(x); + + // addition + { + int addition_result = 0; + + // Add x to addition_result + auto lambda = [&addition_result](int x){ addition_result += x; }; + + + APPLY_MACRO_FOR_EACH( + APPLY_LAMBDA, + 1, + 2, + 3 + ); + + ASSERT_EQ(addition_result, 6); + } + + // string concatenation + { + std::string concatenation_result = ""; + + // Add char to the end of string + auto lambda = [&concatenation_result](char c){ concatenation_result.push_back(c); }; + + APPLY_MACRO_FOR_EACH( + APPLY_LAMBDA, + 'H', + 'e', + 'l', + 'l', + '0', + '.' + ); + + ASSERT_EQ(concatenation_result, "Hell0."); + } +} + +int main( + int argc, + char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 5df120c074df39675194841b0158b854dffa9674 Mon Sep 17 00:00:00 2001 From: jparisu Date: Mon, 5 Sep 2022 14:51:37 +0200 Subject: [PATCH 2/8] Implementation of ENUMERATION_BUILDER Signed-off-by: jparisu --- .../auxiliar/BaseParticipant.hpp | 2 +- .../include/ddsrouter_utils/Log.hpp | 2 +- .../macros/custom_enumeration.hpp | 102 +++------- .../include/ddsrouter_utils/utils.hpp | 2 +- ddsrouter_utils/test/unittest/CMakeLists.txt | 1 - .../test/unittest/macros/CMakeLists.txt | 9 +- .../macros/enumerationBuilderMacrosTest.cpp | 187 ++++-------------- .../unittest/macros/recursiveMacrosTest.cpp | 2 +- .../ddsrouter_yaml/impl/YamlReader.ipp | 2 +- 9 files changed, 71 insertions(+), 238 deletions(-) diff --git a/ddsrouter_core/src/cpp/participant/implementations/auxiliar/BaseParticipant.hpp b/ddsrouter_core/src/cpp/participant/implementations/auxiliar/BaseParticipant.hpp index 2ff2df3fa..ff696b92e 100644 --- a/ddsrouter_core/src/cpp/participant/implementations/auxiliar/BaseParticipant.hpp +++ b/ddsrouter_core/src/cpp/participant/implementations/auxiliar/BaseParticipant.hpp @@ -19,7 +19,7 @@ #ifndef __SRC_DDSROUTERCORE_PARTICIPANT_IMPLEMENTATIONS_AUXILIAR_BASEPARTICIPANT_HPP_ #define __SRC_DDSROUTERCORE_PARTICIPANT_IMPLEMENTATIONS_AUXILIAR_BASEPARTICIPANT_HPP_ -#include +#include #include diff --git a/ddsrouter_utils/include/ddsrouter_utils/Log.hpp b/ddsrouter_utils/include/ddsrouter_utils/Log.hpp index b18b4cd97..f9a4a01ba 100644 --- a/ddsrouter_utils/include/ddsrouter_utils/Log.hpp +++ b/ddsrouter_utils/include/ddsrouter_utils/Log.hpp @@ -22,7 +22,7 @@ // Use FastDDS log #include -#include +#include namespace eprosima { namespace ddsrouter { diff --git a/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp b/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp index 4c8b18744..335b262d2 100644 --- a/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp +++ b/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp @@ -33,88 +33,27 @@ namespace ddsrouter { namespace utils { /** - * @brief This macro creates a Custom Enumeration + * @brief This macro creates a Custom Enumeration with auxiliary functions and variables. * - * A Custom Enumeration is an Enumeration class that internally has a enum class and has several methods to interact - * with it: - * - creation from enum value - * - creation from string - * - conversion to string - * - conversion to int + * An enumeration built with ENUEMERATION_BUILDER has: + * - enum class with name \c enumeration_name and N values, one for each extra argument, and with that exact name. + * - array called \c nammes_ with the names of each element of the enumeration + * as strings of the enum value. + * - \c to_string method to get the string associated with an enumeration value. + * - \c from_string_ method that gives enumeration value from string name. + * - operator << for each enumeration value using to_string . + * - \c N_VALUES_ unsigned int to get the number of elements in the enumeration. * - * @warning Requires a ";" after call + * @arg enumeration_name it sets the enum class name and is used to name variables and methods. + * @arg extra_arguments each of the elements of the enum class. Their conversion to string would use this same name. + *e + * @example + * ENUMERATION_BUILDER(CustomEnum, el1, el2); + * CustomEnum my_value = CustomEnum::el1; // Set my_value as el1 = 0 + * my_value = from_string_CustomEnum("el2"); // Set my_value as el2 = 1 + * to_string(my_value); // = "el2" */ - -// #define ENUMERATION_BUILDER(enumeration_name, ...) \ -// \ -// class enumeration_name \ -// { \ -// public: \ -// \ -// /* Internal enumeration */ \ -// enum class Enum {__VA_ARGS__}; \ -// \ -// /* Constructor from Enumeration */ \ -// enumeration_name(Enum e) : internal_value_(e) {} \ -// \ -// /* Constructor from string */ \ -// enumeration_name(const std::string& s) : internal_value_(from_string_(s)) {} \ -// \ -// /* To string method */ \ -// std::string to_string() const { return names_[static_cast(internal_value_)]; } \ -// \ -// /* To string operator */ \ -// operator std::string() const { return this->to_string(); } \ -// \ -// /* To int operator */ \ -// operator int() const { return static_cast(internal_value_); } \ -// \ -// /* To Enum operator */ \ -// operator Enum() const { return internal_value_; } \ -// \ -// /* Equal comparision */ \ -// bool operator== (const enumeration_name& other) { return this->internal_value_ == other.internal_value_; } \ -// \ -// /* Equal comparision */ \ -// bool operator== (const Enum& other) { return this->internal_value_ == other; } \ -// \ -// /* Not Equal comparision */ \ -// bool operator!= (const enumeration_name& other) { return this->internal_value_ != other.internal_value_; } \ -// \ -// /* Not Equal comparision */ \ -// bool operator!= (const Enum& other) { return this->internal_value_ != other; } \ -// \ -// protected: \ -// \ -// /* From string */ \ -// static Enum from_string_ (const std::string& s) \ -// { \ -// for (int i=0; i(i); \ -// throw eprosima::ddsrouter::utils::InitializationException( \ -// STR_ENTRY << "Not correct name " << s << " for Enum " << STRINGIFY(enumeration_name) << "."); \ -// } \ -// \ -// \ -// /* Names array */ \ -// static const std::array names_; \ -// \ -// /* Internal value */ \ -// Enum internal_value_; \ -// \ -// }; \ -// \ -// /* Serialization operation */ \ -// std::ostream& operator <<(std::ostream& os, const enumeration_name& e) { os << e.to_string(); return os; } \ -// \ -// /* Initialize name arrays */ \ -// const std::array enumeration_name::names_ = \ -// { APPLY_MACRO_FOR_EACH(STRINGIFY_WITH_COMMA, __VA_ARGS__) } - - - - -#define ENUMERATION_BUILDER(enumeration_name, ...) \ +#define ENUMERATION_BUILDER(enumeration_name, ...) \ \ /* Declare enumeration */ \ enum class enumeration_name {__VA_ARGS__}; \ @@ -137,7 +76,10 @@ namespace utils { } \ \ /* Serialization operation */ \ - std::ostream& operator <<(std::ostream& os, const enumeration_name& e) { os << to_string(e); return os; } + std::ostream& operator <<(std::ostream& os, const enumeration_name& e) { os << to_string(e); return os; } \ + \ + /* Number of elements in enumeration */ \ + constexpr const unsigned int N_VALUES_##enumeration_name = COUNT_ARGUMENTS(__VA_ARGS__); } /* namespace utils */ diff --git a/ddsrouter_utils/include/ddsrouter_utils/utils.hpp b/ddsrouter_utils/include/ddsrouter_utils/utils.hpp index 83924ee86..d20b513f9 100644 --- a/ddsrouter_utils/include/ddsrouter_utils/utils.hpp +++ b/ddsrouter_utils/include/ddsrouter_utils/utils.hpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/ddsrouter_utils/test/unittest/CMakeLists.txt b/ddsrouter_utils/test/unittest/CMakeLists.txt index 30b0e8939..b9920d846 100644 --- a/ddsrouter_utils/test/unittest/CMakeLists.txt +++ b/ddsrouter_utils/test/unittest/CMakeLists.txt @@ -21,6 +21,5 @@ add_subdirectory(memory) add_subdirectory(return_code) add_subdirectory(thread_pool) add_subdirectory(time) -add_subdirectory(types) add_subdirectory(utils) add_subdirectory(wait) diff --git a/ddsrouter_utils/test/unittest/macros/CMakeLists.txt b/ddsrouter_utils/test/unittest/macros/CMakeLists.txt index 6395249a0..3a6d5b451 100644 --- a/ddsrouter_utils/test/unittest/macros/CMakeLists.txt +++ b/ddsrouter_utils/test/unittest/macros/CMakeLists.txt @@ -52,7 +52,7 @@ set(TEST_SOURCES set(TEST_LIST count_arguments - apply_APPLY_MACRO_FOR_EACH + apply_macro_for_each ) set(TEST_EXTRA_LIBRARIES @@ -82,12 +82,11 @@ set(TEST_SOURCES ) set(TEST_LIST - construct_enum - construct_string + show_how + from_string to_string - string_operator - int_operator serializator + n_values ) set(TEST_EXTRA_LIBRARIES diff --git a/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp b/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp index a2d44bbe7..61547d5b1 100644 --- a/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp +++ b/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp @@ -19,146 +19,9 @@ #include -// namespace test { - -// ENUMERATION_BUILDER( -// TestCustomEnum, -// el0, -// el1, -// other_element, -// noElement_atAll_00 -// ); - -// constexpr unsigned int NUMBER_OF_ELEMENTS = 4; - -// const std::array enum_values = -// { -// TestCustomEnum::Enum::el0, -// TestCustomEnum::Enum::el1, -// TestCustomEnum::Enum::other_element, -// TestCustomEnum::Enum::noElement_atAll_00, -// }; - -// const std::array class_values = -// { -// TestCustomEnum(TestCustomEnum::Enum::el0), -// TestCustomEnum(TestCustomEnum::Enum::el1), -// TestCustomEnum(TestCustomEnum::Enum::other_element), -// TestCustomEnum(TestCustomEnum::Enum::noElement_atAll_00), -// }; - -// const std::array string_values = -// { -// "el0", -// "el1", -// "other_element", -// "noElement_atAll_00", -// }; - -// } /* namespace test */ - -// /** -// * Construct enumeration of type TestCustomEnum from its values. -// * -// * CASES: -// * x each element inside -// */ -// TEST(enumerationBuilderMacrosTest, construct_enum) -// { -// // x each element inside -// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) -// { -// test::TestCustomEnum value(test::enum_values[i]); -// ASSERT_TRUE(value == test::class_values[i]); -// ASSERT_TRUE(value == test::enum_values[i]); -// } -// } - -// /** -// * Construct enumeration of type TestCustomEnum from a string. -// * -// * CASES: -// * x each element inside -// * - string not in enumeration -// */ -// TEST(enumerationBuilderMacrosTest, construct_string) -// { -// // x each element inside -// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) -// { -// test::TestCustomEnum value(test::string_values[i]); -// ASSERT_TRUE(value == test::class_values[i]); -// ASSERT_TRUE(value == test::enum_values[i]); -// } - -// // string not in enumeration -// ASSERT_THROW(test::TestCustomEnum("noElement_atAll_0") , eprosima::ddsrouter::utils::InitializationException); -// } - -// /** -// * Compare to_string with expected result -// * -// * CASES: -// * x each element inside -// */ -// TEST(enumerationBuilderMacrosTest, to_string) -// { -// // x each element inside -// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) -// { -// ASSERT_EQ(test::class_values[i].to_string(), test::string_values[i]); -// } -// } - -// /** -// * Compare to string cast operator with expected result -// * -// * CASES: -// * x each element inside -// */ -// TEST(enumerationBuilderMacrosTest, string_operator) -// { -// // x each element inside -// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) -// { -// ASSERT_EQ(static_cast(test::class_values[i]), test::string_values[i]); -// } -// } - -// /** -// * Compare to int cast operator with expected result -// * -// * CASES: -// * x each element inside -// */ -// TEST(enumerationBuilderMacrosTest, int_operator) -// { -// // x each element inside -// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) -// { -// ASSERT_EQ(static_cast(test::class_values[i]), i); -// } -// } - -// /** -// * Compare to int cast operator with expected result -// * -// * CASES: -// * x each element inside -// */ -// TEST(enumerationBuilderMacrosTest, serializator) -// { -// // x each element inside -// for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) -// { -// std::stringstream ss; -// ss << test::class_values[i]; -// ASSERT_EQ(ss.str(), test::string_values[i]); -// } -// } - namespace test { +// This will create a TestCustomEnum enum class with these values. ENUMERATION_BUILDER( TestCustomEnum, el0, @@ -167,13 +30,10 @@ ENUMERATION_BUILDER( noElement_atAll_00 ); -ENUMERATION_BUILDER( - TestCustomOtherEnum, - el_0, -); - +// Number of elements in TestCustomEnum constexpr unsigned int NUMBER_OF_ELEMENTS = 4; +// Each of the elements of TestCustomEnum const std::array enum_values = { TestCustomEnum::el0, @@ -182,6 +42,7 @@ const std::array enum_values = TestCustomEnum::noElement_atAll_00, }; +// Each of the names of TestCustomEnum const std::array string_values = { "el0", @@ -190,8 +51,40 @@ const std::array string_values = "noElement_atAll_00", }; +// This tests that two calls to ENUMERATION_BUILDER are possible. +ENUMERATION_BUILDER( + TestCustomOtherEnum, + el0, +); + } /* namespace test */ +/** + * This test only shows how to use the ENUMERATION_BUILDER macro. + */ +TEST(enumerationBuilderMacrosTest, show_how) +{ + // Get a new element of value el0 + test::TestCustomEnum value = test::TestCustomEnum::el0; + + // Compare string of value + ASSERT_EQ("el0", test::to_string(value)); + + // Get it from a string + value = test::from_string_TestCustomEnum("el1"); + + // Compare string of value + ASSERT_EQ("el1", test::to_string(value)); +} + +/** + * Check the N_VALUES variable + */ +TEST(enumerationBuilderMacrosTest, n_values) +{ + ASSERT_EQ(test::N_VALUES_TestCustomEnum, test::NUMBER_OF_ELEMENTS); +} + /** * Construct enumeration of type TestCustomEnum from a string. * @@ -202,7 +95,7 @@ const std::array string_values = TEST(enumerationBuilderMacrosTest, from_string) { // x each element inside - for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) + for (int i = 0; i < test::N_VALUES_TestCustomEnum; i++) { test::TestCustomEnum value = test::from_string_TestCustomEnum(test::string_values[i]); ASSERT_TRUE(value == test::enum_values[i]); @@ -221,14 +114,14 @@ TEST(enumerationBuilderMacrosTest, from_string) TEST(enumerationBuilderMacrosTest, to_string) { // x each element inside - for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) + for (int i = 0; i < test::N_VALUES_TestCustomEnum; i++) { ASSERT_EQ(test::to_string(test::enum_values[i]), test::string_values[i]); } } /** - * Compare to int cast operator with expected result + * Compare serializator method of each value of enumeration * * CASES: * x each element inside @@ -236,7 +129,7 @@ TEST(enumerationBuilderMacrosTest, to_string) TEST(enumerationBuilderMacrosTest, serializator) { // x each element inside - for (int i = 0; i < test::NUMBER_OF_ELEMENTS; i++) + for (int i = 0; i < test::N_VALUES_TestCustomEnum; i++) { std::stringstream ss; ss << test::enum_values[i]; diff --git a/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp b/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp index 8f7ab083f..31be41c61 100644 --- a/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp +++ b/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp @@ -75,7 +75,7 @@ TEST(recursiveMacrosTest, count_arguments) * addition * string concatenation */ -TEST(recursiveMacrosTest, apply_APPLY_MACRO_FOR_EACH) +TEST(recursiveMacrosTest, apply_macro_for_each) { #define APPLY_LAMBDA(x) lambda(x); diff --git a/ddsrouter_yaml/include/ddsrouter_yaml/impl/YamlReader.ipp b/ddsrouter_yaml/include/ddsrouter_yaml/impl/YamlReader.ipp index 046fc95a2..f1d91a1e4 100644 --- a/ddsrouter_yaml/include/ddsrouter_yaml/impl/YamlReader.ipp +++ b/ddsrouter_yaml/include/ddsrouter_yaml/impl/YamlReader.ipp @@ -21,7 +21,7 @@ #define _DDSROUTERYAML_IMPL_YAMLREADER_IPP_ #include -#include +#include #include namespace eprosima { From 0b614cab137ded00222f0c824dc70a8f6f04b802 Mon Sep 17 00:00:00 2001 From: jparisu Date: Mon, 5 Sep 2022 15:25:27 +0200 Subject: [PATCH 3/8] Fix windows compilation Signed-off-by: jparisu --- .../test/unittest/macros/CMakeLists.txt | 5 +++ .../unittest/macros/recursiveMacrosTest.cpp | 44 +++++++++---------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/ddsrouter_utils/test/unittest/macros/CMakeLists.txt b/ddsrouter_utils/test/unittest/macros/CMakeLists.txt index 3a6d5b451..ed53dcbaf 100644 --- a/ddsrouter_utils/test/unittest/macros/CMakeLists.txt +++ b/ddsrouter_utils/test/unittest/macros/CMakeLists.txt @@ -48,6 +48,9 @@ set(TEST_NAME recursiveMacrosTest) set(TEST_SOURCES recursiveMacrosTest.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/Formatter.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/exception/Exception.cpp + ${PROJECT_SOURCE_DIR}/src/cpp/utils.cpp ) set(TEST_LIST @@ -56,6 +59,8 @@ set(TEST_LIST ) set(TEST_EXTRA_LIBRARIES + fastcdr + fastrtps ) set(TEST_NEEDED_SOURCES diff --git a/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp b/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp index 31be41c61..33ce901b2 100644 --- a/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp +++ b/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp @@ -16,6 +16,7 @@ #include #include +#include /** * Test \c COUNT_ARGUMENTS macro @@ -78,44 +79,41 @@ TEST(recursiveMacrosTest, count_arguments) TEST(recursiveMacrosTest, apply_macro_for_each) { -#define APPLY_LAMBDA(x) lambda(x); +#define ADD_1(x) x += 1; // addition { - int addition_result = 0; - - // Add x to addition_result - auto lambda = [&addition_result](int x){ addition_result += x; }; - + int x = 1; + int y = 2; + int z = 3; APPLY_MACRO_FOR_EACH( - APPLY_LAMBDA, - 1, - 2, - 3 + ADD_1, + x, + y, + z ); - ASSERT_EQ(addition_result, 6); + ASSERT_EQ(x, 2); + ASSERT_EQ(y, 3); + ASSERT_EQ(z, 4); } +#define TO_LOWERCASE(x) eprosima::ddsrouter::utils::to_lowercase(x); + // string concatenation { - std::string concatenation_result = ""; - - // Add char to the end of string - auto lambda = [&concatenation_result](char c){ concatenation_result.push_back(c); }; + std::string hello = "HELLO"; + std::string bye = "ByE"; APPLY_MACRO_FOR_EACH( - APPLY_LAMBDA, - 'H', - 'e', - 'l', - 'l', - '0', - '.' + TO_LOWERCASE, + hello, + bye ); - ASSERT_EQ(concatenation_result, "Hell0."); + ASSERT_EQ(hello, "hello"); + ASSERT_EQ(bye, "bye"); } } From 6e4a9157a0d0beb45ba22eab2c4041b6799285aa Mon Sep 17 00:00:00 2001 From: jparisu Date: Mon, 5 Sep 2022 16:56:05 +0200 Subject: [PATCH 4/8] Add preprocessor to windows compilation Signed-off-by: jparisu --- .../cpp_common/configure_project_cpp.cmake | 3 ++ .../cmake/cpp_common/cpp_flags.cmake | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 ddsrouter_cmake/cmake/cpp_common/cpp_flags.cmake diff --git a/ddsrouter_cmake/cmake/cpp_common/configure_project_cpp.cmake b/ddsrouter_cmake/cmake/cpp_common/configure_project_cpp.cmake index 9e1b2e742..0113cc73b 100644 --- a/ddsrouter_cmake/cmake/cpp_common/configure_project_cpp.cmake +++ b/ddsrouter_cmake/cmake/cpp_common/configure_project_cpp.cmake @@ -57,6 +57,9 @@ macro(configure_project_cpp) activate_code_coverage() endif() + # Set custom C++ Flags + custom_cpp_flags() + # Finish macro message(STATUS "C++ Project ${MODULE_NAME_LARGE} configured.") diff --git a/ddsrouter_cmake/cmake/cpp_common/cpp_flags.cmake b/ddsrouter_cmake/cmake/cpp_common/cpp_flags.cmake new file mode 100644 index 000000000..073ce08c9 --- /dev/null +++ b/ddsrouter_cmake/cmake/cpp_common/cpp_flags.cmake @@ -0,0 +1,28 @@ +# Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############################################################################### +# CMake Build Type +############################################################################### + +# Set custom CMAKE_CXX_FLAGS +macro(custom_cpp_flags) + + # Only for windows + if(MSVC OR MSVC_IDE) + # Set standard preprocessor + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:preprocessor") + endif() + +endmacro() From fb099ba7cc3667dfd75ade4cc8c6a83ba82ca6e1 Mon Sep 17 00:00:00 2001 From: jparisu Date: Tue, 6 Sep 2022 07:43:51 +0200 Subject: [PATCH 5/8] Fix windows compilation external link Signed-off-by: jparisu --- ddsrouter_utils/test/unittest/macros/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ddsrouter_utils/test/unittest/macros/CMakeLists.txt b/ddsrouter_utils/test/unittest/macros/CMakeLists.txt index ed53dcbaf..cce5896c3 100644 --- a/ddsrouter_utils/test/unittest/macros/CMakeLists.txt +++ b/ddsrouter_utils/test/unittest/macros/CMakeLists.txt @@ -61,6 +61,7 @@ set(TEST_LIST set(TEST_EXTRA_LIBRARIES fastcdr fastrtps + $<$:iphlpapi$Shlwapi> ) set(TEST_NEEDED_SOURCES From 27845c08928c843d0255fad59bd7fe5d63b51f9f Mon Sep 17 00:00:00 2001 From: jparisu Date: Tue, 6 Sep 2022 08:07:42 +0200 Subject: [PATCH 6/8] Fix windows compilation 2019 WSDK Signed-off-by: jparisu --- .../install-router-subpackage-windows/action.yml | 5 +++++ .github/workflows/test.yml | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/.github/actions/install-router-subpackage-windows/action.yml b/.github/actions/install-router-subpackage-windows/action.yml index a560f7f11..1cf514487 100644 --- a/.github/actions/install-router-subpackage-windows/action.yml +++ b/.github/actions/install-router-subpackage-windows/action.yml @@ -1,6 +1,10 @@ name: Install DDS Router subpackages description: Install and setup DDS Router subpackages for linking and building application in Windows inputs: + cmake_extra_args: + description: 'Specifies cmake arguments different from default' + required: false + default: ' ' cmake_build_type: description: 'Specifies the build type on single-configuration generators' required: true @@ -17,6 +21,7 @@ runs: - run: > cmake -DCMAKE_PREFIX_PATH='C:\Program Files\gtest;C:\Program Files\yamlcpp;C:\Program Files;${{ github.workspace }}\..\fastdds\install' ` -DCMAKE_CXX_FLAGS="/WX /EHsc" -DBUILD_TOOL_TESTS=ON -DBUILD_LIBRARY_TESTS=ON ` + ${{ inputs.cmake_extra_args }} ` -B build\${{ inputs.subpackage }} -A x64 -T host=x64 DDS-Router/${{ inputs.subpackage_dir }}; cmake --build build\${{ inputs.subpackage }} --config ${{ inputs.cmake_build_type }} --target install; diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3a7a0a890..9c1a54b37 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -102,9 +102,20 @@ jobs: subpackage: ddsrouter_cmake subpackage_dir: ddsrouter_cmake + # This is needed for windows 2019 to use /Zc:preprocessor to use c++ std preprocessor due to a windows non bug + - name: Set Env Var for 2019 WSDK + run: | + echo ("W2019_CMAKE_EXTRA_ARGS=-DCMAKE_SYSTEM_VERSION=10.0.19041.0") >> $env:GITHUB_ENV + if: contains( matrix.windows-version , '2019') + + # TODO: remove + - name: Test Env Var for 2019 WSDK + run: echo "${{ env.W2019_CMAKE_EXTRA_ARGS }}" + - name: Install ddsrouter_utils uses: ./DDS-Router/.github/actions/install-router-subpackage-windows with: + cmake_extra_args: ${{ env.W2019_CMAKE_EXTRA_ARGS }} cmake_build_type: ${{ matrix.cmake-config }} subpackage: ddsrouter_utils subpackage_dir: ddsrouter_utils From 836c4b37b705ba6fe1fe89d5fb1a0bd83ab0da8c Mon Sep 17 00:00:00 2001 From: jparisu Date: Tue, 6 Sep 2022 08:45:51 +0200 Subject: [PATCH 7/8] apply suggestions Signed-off-by: jparisu --- .github/workflows/test.yml | 9 +++------ .../ddsrouter_utils/macros/custom_enumeration.hpp | 9 +++++++-- .../unittest/macros/enumerationBuilderMacrosTest.cpp | 9 ++++++++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9c1a54b37..9ee5c5a30 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -102,16 +102,13 @@ jobs: subpackage: ddsrouter_cmake subpackage_dir: ddsrouter_cmake - # This is needed for windows 2019 to use /Zc:preprocessor to use c++ std preprocessor due to a windows non bug - - name: Set Env Var for 2019 WSDK + # This is needed for windows 2019 to use /Zc:preprocessor to use c++ std preprocessor for ENUMERATION_BUILDER + # due to a windows 2019 SDK non bug + - name: Set environment variables for Windows 2019 build run: | echo ("W2019_CMAKE_EXTRA_ARGS=-DCMAKE_SYSTEM_VERSION=10.0.19041.0") >> $env:GITHUB_ENV if: contains( matrix.windows-version , '2019') - # TODO: remove - - name: Test Env Var for 2019 WSDK - run: echo "${{ env.W2019_CMAKE_EXTRA_ARGS }}" - - name: Install ddsrouter_utils uses: ./DDS-Router/.github/actions/install-router-subpackage-windows with: diff --git a/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp b/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp index 335b262d2..10277a8f4 100644 --- a/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp +++ b/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp @@ -1,4 +1,4 @@ -// Copyright 2021 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -46,7 +46,9 @@ namespace utils { * * @arg enumeration_name it sets the enum class name and is used to name variables and methods. * @arg extra_arguments each of the elements of the enum class. Their conversion to string would use this same name. - *e + * + * @note empty custom enumerations are not allowed, even when empty enum class are. + * * @example * ENUMERATION_BUILDER(CustomEnum, el1, el2); * CustomEnum my_value = CustomEnum::el1; // Set my_value as el1 = 0 @@ -55,6 +57,9 @@ namespace utils { */ #define ENUMERATION_BUILDER(enumeration_name, ...) \ \ + /* Forbid empty enumerations */ \ + static_assert( COUNT_ARGUMENTS(__VA_ARGS__) , "Empty Enumerations are not allowed."); \ + \ /* Declare enumeration */ \ enum class enumeration_name {__VA_ARGS__}; \ \ diff --git a/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp b/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp index 61547d5b1..63b22fcbf 100644 --- a/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp +++ b/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp @@ -54,8 +54,15 @@ const std::array string_values = // This tests that two calls to ENUMERATION_BUILDER are possible. ENUMERATION_BUILDER( TestCustomOtherEnum, - el0, + el0 +); + +// This should be forbidden and would not compile +/* +ENUMERATION_BUILDER( + TestEmptyEnum ); +*/ } /* namespace test */ From b72cc34b368d1a434ca2e0b2b31fafd016c1d9d8 Mon Sep 17 00:00:00 2001 From: jparisu Date: Tue, 6 Sep 2022 08:45:56 +0200 Subject: [PATCH 8/8] uncrustify Signed-off-by: jparisu --- .../macros/custom_enumeration.hpp | 21 ++++++++++--------- .../macros/recursive_macros.hpp | 10 ++++----- .../macros/enumerationBuilderMacrosTest.cpp | 12 +++++------ .../test/unittest/macros/macrosTest.cpp | 8 +++---- .../unittest/macros/recursiveMacrosTest.cpp | 18 ++++++++-------- 5 files changed, 35 insertions(+), 34 deletions(-) diff --git a/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp b/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp index 10277a8f4..a609a6b86 100644 --- a/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp +++ b/ddsrouter_utils/include/ddsrouter_utils/macros/custom_enumeration.hpp @@ -58,33 +58,34 @@ namespace utils { #define ENUMERATION_BUILDER(enumeration_name, ...) \ \ /* Forbid empty enumerations */ \ - static_assert( COUNT_ARGUMENTS(__VA_ARGS__) , "Empty Enumerations are not allowed."); \ + static_assert( COUNT_ARGUMENTS(__VA_ARGS__), "Empty Enumerations are not allowed."); \ \ /* Declare enumeration */ \ - enum class enumeration_name {__VA_ARGS__}; \ + enum class enumeration_name {__VA_ARGS__ \ + }; \ \ /* Initialize name arrays */ \ - const std::array names_##enumeration_name = \ - { APPLY_MACRO_FOR_EACH(STRINGIFY_WITH_COMMA, __VA_ARGS__) }; \ + const std::array names_ ## enumeration_name = \ + { APPLY_MACRO_FOR_EACH(STRINGIFY_WITH_COMMA, __VA_ARGS__) }; \ \ /* To string method */ \ const std::string& to_string(const enumeration_name& e) \ - { return names_##enumeration_name[static_cast(e)]; } \ + { return names_ ## enumeration_name[static_cast(e)]; } \ \ /* From string */ \ - enumeration_name from_string_##enumeration_name(const std::string& s) \ + enumeration_name from_string_ ## enumeration_name(const std::string& s) \ { \ - for (int i=0; i(i); \ + for (int i = 0; i < COUNT_ARGUMENTS(__VA_ARGS__); i++) \ + if (names_ ## enumeration_name[i] == s)return static_cast(i); \ throw eprosima::ddsrouter::utils::InitializationException( \ - STR_ENTRY << "Not correct name " << s << " for Enum " << STRINGIFY(enumeration_name) << "."); \ + STR_ENTRY << "Not correct name " << s << " for Enum " << STRINGIFY(enumeration_name) << "."); \ } \ \ /* Serialization operation */ \ std::ostream& operator <<(std::ostream& os, const enumeration_name& e) { os << to_string(e); return os; } \ \ /* Number of elements in enumeration */ \ - constexpr const unsigned int N_VALUES_##enumeration_name = COUNT_ARGUMENTS(__VA_ARGS__); + constexpr const unsigned int N_VALUES_ ## enumeration_name = COUNT_ARGUMENTS(__VA_ARGS__); } /* namespace utils */ diff --git a/ddsrouter_utils/include/ddsrouter_utils/macros/recursive_macros.hpp b/ddsrouter_utils/include/ddsrouter_utils/macros/recursive_macros.hpp index 603211543..a799ec046 100644 --- a/ddsrouter_utils/include/ddsrouter_utils/macros/recursive_macros.hpp +++ b/ddsrouter_utils/include/ddsrouter_utils/macros/recursive_macros.hpp @@ -89,11 +89,11 @@ namespace utils { * * @note this is useful for \c APPLY_MACRO_FOR_EACH macro. */ -#define _GET_NINTH_ARGUMENT(_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) \ +#define _GET_NINTH_ARGUMENT(_1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) \ NAME -#define _APPLY_MACRO_FOR_EACH__UP_TO_NINE(action,...) \ - _GET_NINTH_ARGUMENT(__VA_ARGS__,_FE_9,_FE_8,_FE_7,_FE_6,_FE_5,_FE_4,_FE_3,_FE_2,_FE_1)(action,__VA_ARGS__) +#define _APPLY_MACRO_FOR_EACH__UP_TO_NINE(action, ...) \ + _GET_NINTH_ARGUMENT(__VA_ARGS__, _FE_9, _FE_8, _FE_7, _FE_6, _FE_5, _FE_4, _FE_3, _FE_2, _FE_1)(action, __VA_ARGS__) /** * @brief Execute \c action (must be a macro) for every argument after it. @@ -105,8 +105,8 @@ namespace utils { * @example * APPLY_MACRO_FOR_EACH(print, el1, el2, el3) => print(el1); print(el2); print(el3); */ -#define APPLY_MACRO_FOR_EACH(action,...) \ - _APPLY_MACRO_FOR_EACH__UP_TO_NINE(action,__VA_ARGS__) +#define APPLY_MACRO_FOR_EACH(action, ...) \ + _APPLY_MACRO_FOR_EACH__UP_TO_NINE(action, __VA_ARGS__) } /* namespace utils */ } /* namespace ddsrouter */ diff --git a/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp b/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp index 63b22fcbf..5aa1fab8a 100644 --- a/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp +++ b/ddsrouter_utils/test/unittest/macros/enumerationBuilderMacrosTest.cpp @@ -28,7 +28,7 @@ ENUMERATION_BUILDER( el1, other_element, noElement_atAll_00 -); + ); // Number of elements in TestCustomEnum constexpr unsigned int NUMBER_OF_ELEMENTS = 4; @@ -55,14 +55,14 @@ const std::array string_values = ENUMERATION_BUILDER( TestCustomOtherEnum, el0 -); + ); // This should be forbidden and would not compile /* -ENUMERATION_BUILDER( + ENUMERATION_BUILDER( TestEmptyEnum -); -*/ + ); + */ } /* namespace test */ @@ -109,7 +109,7 @@ TEST(enumerationBuilderMacrosTest, from_string) } // string not in enumeration - ASSERT_THROW(test::from_string_TestCustomEnum("el_0") , eprosima::ddsrouter::utils::InitializationException); + ASSERT_THROW(test::from_string_TestCustomEnum("el_0"), eprosima::ddsrouter::utils::InitializationException); } /** diff --git a/ddsrouter_utils/test/unittest/macros/macrosTest.cpp b/ddsrouter_utils/test/unittest/macros/macrosTest.cpp index e7d80f52b..c1b92c843 100644 --- a/ddsrouter_utils/test/unittest/macros/macrosTest.cpp +++ b/ddsrouter_utils/test/unittest/macros/macrosTest.cpp @@ -31,12 +31,12 @@ TEST(macrosTest, stringify) ASSERT_EQ( std::string(STRINGIFY(abcdefghijkl)), std::string("abcdefghijkl") - ); + ); ASSERT_EQ( std::string(STRINGIFY(k1)), std::string("k1") - ); + ); } // variable name @@ -46,14 +46,14 @@ TEST(macrosTest, stringify) ASSERT_EQ( std::string(STRINGIFY(_random_value)), std::string("_random_value") - ); + ); // String std::string _random_string = "other value"; ASSERT_EQ( std::string(STRINGIFY(_random_string)), std::string("_random_string") - ); + ); } } diff --git a/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp b/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp index 33ce901b2..b9afe412b 100644 --- a/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp +++ b/ddsrouter_utils/test/unittest/macros/recursiveMacrosTest.cpp @@ -34,7 +34,7 @@ TEST(recursiveMacrosTest, count_arguments) ASSERT_EQ( 0, COUNT_ARGUMENTS() - ); + ); } // 1 @@ -43,8 +43,8 @@ TEST(recursiveMacrosTest, count_arguments) 1, COUNT_ARGUMENTS( "el1" - ) - ); + ) + ); } // 5 @@ -53,8 +53,8 @@ TEST(recursiveMacrosTest, count_arguments) 5, COUNT_ARGUMENTS( "el1", "el2", "el3", "el4", "el5" - ) - ); + ) + ); } // 9 @@ -64,8 +64,8 @@ TEST(recursiveMacrosTest, count_arguments) COUNT_ARGUMENTS( "el1", "el2", "el3", "el4", "el5", "el1", "el2", "el3", "el4" - ) - ); + ) + ); } } @@ -92,7 +92,7 @@ TEST(recursiveMacrosTest, apply_macro_for_each) x, y, z - ); + ); ASSERT_EQ(x, 2); ASSERT_EQ(y, 3); @@ -110,7 +110,7 @@ TEST(recursiveMacrosTest, apply_macro_for_each) TO_LOWERCASE, hello, bye - ); + ); ASSERT_EQ(hello, "hello"); ASSERT_EQ(bye, "bye");