From 09aa5b6e1f64c35d25f62ba1ae46ca8c9c9a6845 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Wed, 14 Dec 2022 15:40:38 +0100 Subject: [PATCH 01/49] Refs 16497. CMake upgrade. Signed-off-by: Miguel Barro --- CMakeLists.txt | 104 ++++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 57 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5b9bbea..8f189299 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ ##################################################################################### # Top xtypes build system ##################################################################################### -cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.16.3 FATAL_ERROR) project(xtypes VERSION "0.1.0" @@ -13,21 +13,18 @@ option(XTYPES_BUILD_EXAMPLES "Build examples." OFF) option(XTYPES_EXCEPTIONS "Enable xtypes exceptions in release (which are asserts in debug)." OFF) option(XTYPES_BUILD_TOOLS "Build tools." OFF) -if(XTYPES_EXCEPTIONS) - #add_compile_definitions(XTYPES_EXCEPTIONS) #CMake 3.16 - add_definitions(-DXTYPES_EXCEPTIONS) -else() - remove_definitions(-DXTYPES_EXCEPTIONS) -endif() - set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) ##################################################################################### # Library ##################################################################################### -add_library(${PROJECT_NAME} INTERFACE) +add_library(xtypes INTERFACE) +add_library(eprosima::xtypes ALIAS xtypes) +if(XTYPES_EXCEPTIONS) + target_compile_definitions(xtypes INTERFACE XTYPES_EXCEPTIONS) +endif() # Download the cpp-peglib header file needed file(DOWNLOAD @@ -35,7 +32,18 @@ file(DOWNLOAD ${PROJECT_SOURCE_DIR}/thirdparty/cpp-peglib/peglib.h ) -target_include_directories(${PROJECT_NAME} +# MSVC always returns __cplusplus = 199711 unles we use the flag /Zc:__cplusplus then it follows the GNU behavior +if(MSVC) + execute_process(COMMAND + powershell -Command [=[ + $header = gi thirdparty/cpp-peglib/peglib.h; + (cat $header | % { $_ -replace '__cplusplus', '_MSVC_LANG' } ) | Set-Content $header + ]=] + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) +endif(MSVC) + +target_include_directories(xtypes INTERFACE $ $ @@ -43,10 +51,7 @@ target_include_directories(${PROJECT_NAME} $ ) -target_compile_features(${PROJECT_NAME} - INTERFACE - cxx_std_17 - ) +target_compile_features(xtypes INTERFACE cxx_std_17) ##################################################################################### # Tools @@ -68,28 +73,22 @@ macro(compile_tool) PUBLIC Threads::Threads PRIVATE - ${PROJECT_NAME} + xtypes ) target_compile_options(${TOOL_NAME} INTERFACE - $<$:-Wall> - $<$:-Wextra> - ) - - set_target_properties(${TOOL_NAME} - PROPERTIES - CXX_STANDARD 17 + $<$:-Wall -Wextra> ) endmacro() find_program(NODERED_EXECUTABLE NAMES node-red node-red@ PATH_SUFFIXES bin) if(XTYPES_BUILD_TOOLS OR NODERED_EXECUTABLE) - compile_tool(${PROJECT_NAME}_idl_validator SOURCE tools/idl_validator.cpp) + compile_tool(xtypes_idl_validator SOURCE tools/idl_validator.cpp) if (NODERED_EXECUTABLE) - file(WRITE $ENV{HOME}/idl_parser_path.txt "${PROJECT_BINARY_DIR}") + file(WRITE $ENV{TMP}/idl_parser_path.txt "${PROJECT_BINARY_DIR}") message("${PROJECT_BINARY_DIR}") endif() # ... @@ -115,26 +114,20 @@ macro(compile_example) PUBLIC Threads::Threads PRIVATE - ${PROJECT_NAME} + xtypes ) target_compile_options(${EXAMPLE_NAME} INTERFACE - $<$:-Wall> - $<$:-Wextra> - ) - - set_target_properties(${EXAMPLE_NAME} - PROPERTIES - CXX_STANDARD 17 + $<$:-Wall -Wextra> ) endmacro() if(XTYPES_BUILD_EXAMPLES) - compile_example(${PROJECT_NAME}_example_complex_type SOURCE examples/complex_type.cpp) - compile_example(${PROJECT_NAME}_example_module SOURCE examples/module.cpp) - compile_example(${PROJECT_NAME}_example_iterators SOURCE examples/iterators.cpp) - compile_example(${PROJECT_NAME}_example_exceptions_asserts SOURCE examples/exceptions_asserts.cpp) + compile_example(xtypes_example_complex_type SOURCE examples/complex_type.cpp) + compile_example(xtypes_example_module SOURCE examples/module.cpp) + compile_example(xtypes_example_iterators SOURCE examples/iterators.cpp) + compile_example(xtypes_example_exceptions_asserts SOURCE examples/exceptions_asserts.cpp) # ... endif() @@ -158,11 +151,6 @@ macro(compile_test) libgtest ) - set_target_properties(${TEST_NAME} - PROPERTIES - CXX_STANDARD 17 - ) - add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) endmacro() @@ -171,7 +159,7 @@ if(XTYPES_BUILD_TESTS) include(test/gtest.cmake) enable_testing() - compile_test(${PROJECT_NAME}_test_unitary SOURCE + compile_test(xtypes_test_unitary SOURCE test/unitary/xtypes/main.cpp test/unitary/xtypes/primitive_types.cpp test/unitary/xtypes/collection_types.cpp @@ -184,19 +172,19 @@ if(XTYPES_BUILD_TESTS) test/unitary/xtypes/dynamicdata_operators.cpp ) - compile_test(${PROJECT_NAME}_test_unitary_no_memcheck SOURCE + compile_test(xtypes_test_unitary_no_memcheck SOURCE test/unitary/xtypes/main.cpp test/unitary/xtypes/no_memcheck_tests.cpp) - compile_test(${PROJECT_NAME}_idl_parser_test_unitary SOURCE + compile_test(xtypes_idl_parser_test_unitary SOURCE test/unitary/parser/module.cpp test/unitary/parser/parser_test.cpp) - compile_test(${PROJECT_NAME}_idl_parser_roundtrip SOURCE test/unitary/parser/roundtrip.cpp) - compile_test(${PROJECT_NAME}_idl_generator_dependencies SOURCE test/unitary/generator/dependencies.cpp) + compile_test(xtypes_idl_parser_roundtrip SOURCE test/unitary/parser/roundtrip.cpp) + compile_test(xtypes_idl_generator_dependencies SOURCE test/unitary/generator/dependencies.cpp) # ... # Set test with label NoMemoryCheck - set_property(TEST ${PROJECT_NAME}_test_unitary_no_memcheck PROPERTY LABELS "NoMemoryCheck") + set_property(TEST xtypes_test_unitary_no_memcheck PROPERTY LABELS "NoMemoryCheck") # Copy IDL files configure_file( @@ -234,9 +222,9 @@ include(CMakePackageConfigHelpers) configure_package_config_file( ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in - ${PROJECT_BINARY_DIR}/cmake/config/${PROJECT_NAME}-config.cmake + ${PROJECT_BINARY_DIR}/cmake/config/xtypes-config.cmake INSTALL_DESTINATION - ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/cmake + ${CMAKE_INSTALL_DATADIR}/xtypes/cmake PATH_VARS BIN_INSTALL_DIR INCLUDE_INSTALL_DIR @@ -245,7 +233,7 @@ configure_package_config_file( ) write_basic_package_version_file( - ${PROJECT_BINARY_DIR}/cmake/config/${PROJECT_NAME}-config-version.cmake + ${PROJECT_BINARY_DIR}/cmake/config/xtypes-config-version.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY @@ -254,9 +242,9 @@ write_basic_package_version_file( install( TARGETS - ${PROJECT_NAME} + xtypes EXPORT - ${PROJECT_NAME}-targets + xtypes-targets RUNTIME DESTINATION ${BIN_INSTALL_DIR} LIBRARY DESTINATION @@ -285,15 +273,17 @@ install( install( EXPORT - ${PROJECT_NAME}-targets + xtypes-targets + NAMESPACE + eprosima DESTINATION - ${DATA_INSTALL_DIR}/${PROJECT_NAME}/cmake + ${DATA_INSTALL_DIR}/xtypes/cmake ) install( FILES - ${PROJECT_BINARY_DIR}/cmake/config/${PROJECT_NAME}-config.cmake - ${PROJECT_BINARY_DIR}/cmake/config/${PROJECT_NAME}-config-version.cmake + ${PROJECT_BINARY_DIR}/cmake/config/xtypes-config.cmake + ${PROJECT_BINARY_DIR}/cmake/config/xtypes-config-version.cmake DESTINATION - ${DATA_INSTALL_DIR}/${PROJECT_NAME}/cmake + ${DATA_INSTALL_DIR}/xtypes/cmake ) From 9759c2ee8bdb9a0c23aaad1bb64e833a94c1aead Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 16 Dec 2022 13:36:34 +0100 Subject: [PATCH 02/49] Refs 16497. Fixing cross-platform issues. Signed-off-by: Miguel Barro --- CMakeLists.txt | 9 ++- include/xtypes/Assert.hpp | 85 ++++++++++++++++++++++++- include/xtypes/idl/parser.hpp | 24 ++++--- test/unitary/generator/dependencies.cpp | 7 +- 4 files changed, 112 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f189299..521f8484 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,14 @@ target_include_directories(xtypes $ ) -target_compile_features(xtypes INTERFACE cxx_std_17) +target_compile_features(xtypes INTERFACE cxx_std_17 cxx_variadic_macros) + +if(MSVC) + # target_compile_features() only enforces standard values like cxx_std_17. All other values like + # cxx_variadic_macros are not enforced using flags but only will generate an error if not available. + # CMake docs is misguiding (see cmGeneratorTarget::ComputeCompileFeatures implementation). + target_compile_options(xtypes INTERFACE /Zc:preprocessor) +endif(MSVC) ##################################################################################### # Tools diff --git a/include/xtypes/Assert.hpp b/include/xtypes/Assert.hpp index 63640b65..cd6fdb8e 100644 --- a/include/xtypes/Assert.hpp +++ b/include/xtypes/Assert.hpp @@ -18,7 +18,6 @@ #ifndef EPROSIMA_XTYPES_ASSERT_HPP_ #define EPROSIMA_XTYPES_ASSERT_HPP_ -#include #include #include @@ -27,6 +26,88 @@ #define xtypes_assert2_(cond, msg) xtypes_assert3_(cond, msg, false) +#ifdef WIN32 + +#ifndef _WINDOWS_ +# define NOMINMAX +# define WIN32_LEAN_AND_MEAN +# include +#endif + +#include +#include + +namespace { + // auxiliary structure + struct symbol_desc : SYMBOL_INFO + { + CHAR [1023]; // name buffer + + symbol_desc() + { + SizeOfStruct = sizeof(SYMBOL_INFO); + MaxNameLen = 1024; + } + }; +} + +#define xtypes_assert3_(cond, msg, bt) \ + { \ + if (!(cond)) \ + { \ + using namespace std; \ + using tstring = basic_string; \ + \ + stringstream ss__; \ + ss__ << "[XTYPES]: "; \ + ss__ << __FILE__ << ":" << __LINE__ << " - "; \ + ss__ << "Assertion failed with message: "; \ + ss__ << msg << endl; \ + if (bt) \ + { \ + HANDLE hProcess = GetCurrentProcess(); \ + \ + if (SymInitialize(hProcess, NULL, TRUE)) \ + { \ + symbol_desc symbol; \ + void* callstack[128]; \ + \ + int frames = CaptureStackBackTrace(0, 128, callstack, NULL); \ + \ + for( int i = 0; i < frames; ++i) \ + { \ + SymFromAddr( hProcess, static_cast(callstack[i]), 0, &symbol); \ + tstring name = symbol.Name; \ + if (name.empty()) \ + { \ + name = "unknown symbol"; \ + } \ + \ + ss__ << left << setw(4) << (frames -i -1) << showbase << hex \ + << setw(19) << symbol.Address << right << name << dec << endl; \ + } \ + \ + if (!SymCleanup(hProcess)) \ + { \ + DWORD error = GetLastError(); \ + ss__ << "SymCleanup returned error : " << error << endl; \ + } \ + } \ + else \ + { \ + DWORD error = GetLastError(); \ + ss__ << "SymInitialize returned error : " << error << endl; \ + } \ + } \ + cerr << ss__.str() << endl; \ + abort(); \ + } \ + } \ + +#else // WIN32 + +#include + #define xtypes_assert3_(cond, msg, bt) \ { \ if (!(cond)) \ @@ -53,6 +134,8 @@ } \ } \ +#endif // WIN32 + #else // NDEBUG #define xtypes_assert2_(cond, msg) diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 618acd48..513f50bc 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -31,15 +31,16 @@ #include #include -#include -#include -#include -#include +#include #include +#include +#include #include +#include +#include #include -#include #include +#include namespace peg { @@ -284,8 +285,14 @@ class Parser , context_(nullptr) { parser_.enable_ast(); - parser_.log = std::bind(&Parser::parser_log_cb_, this, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3); + parser_.set_logger( + std::function( + std::bind( + &Parser::parser_log_cb_, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3))); } Context parse( @@ -441,7 +448,8 @@ class Parser void parser_log_cb_( size_t l, size_t c, - const std::string& msg) const + const std::string& msg + ) const { context_->log(log::DEBUG, "PEGLIB_PARSER", msg + " (" + std::to_string( l - CPP_PEGLIB_LINE_COUNT_ERROR) + ":" + std::to_string(c) + ")"); diff --git a/test/unitary/generator/dependencies.cpp b/test/unitary/generator/dependencies.cpp index e1d46c0f..75409387 100644 --- a/test/unitary/generator/dependencies.cpp +++ b/test/unitary/generator/dependencies.cpp @@ -120,11 +120,12 @@ void generation_roundtrip_test( } std::string gen_idl = idl::generate(root); - // Debug - // std::cout << "===========================================" << std::endl \ + /* Debug + std::cout << "===========================================" << std::endl \ << gen_idl \ << "===========================================" << std::endl; - //Parse again and check if it went as expected + Parse again and check if it went as expected + */ idl::Context context = idl::parse(gen_idl); ASSERT_TRUE(context.success); From d8b782791f196f19a2d1a764211294f745001b39 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 16 Dec 2022 14:17:49 +0100 Subject: [PATCH 03/49] Refs 16497. Fixing cross-platform issues. Signed-off-by: Miguel Barro --- test/unitary/xtypes/collection_types.cpp | 8 ++++++++ test/unitary/xtypes/dynamicdata_operators.cpp | 16 ++++++++-------- test/unitary/xtypes/no_memcheck_tests.cpp | 10 +++++++++- test/unitary/xtypes/primitive_types.cpp | 2 +- test/unitary/xtypes/struct_type.cpp | 2 +- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/test/unitary/xtypes/collection_types.cpp b/test/unitary/xtypes/collection_types.cpp index fc875a15..fe858280 100644 --- a/test/unitary/xtypes/collection_types.cpp +++ b/test/unitary/xtypes/collection_types.cpp @@ -169,7 +169,11 @@ TEST (CollectionTypes, primitive_arrays) check_primitive_array(25000000000); check_primitive_array(250.76653); check_primitive_array(250.76653e40); +#ifdef WIN32 + check_primitive_array(1.797e308L); +#else check_primitive_array(250.76653e1000l); +#endif // WIN32 check_primitive_array('L'); check_primitive_array(L'G'); } @@ -433,7 +437,11 @@ TEST (CollectionTypes, primitive_sequences) check_primitive_seq(25000000000); check_primitive_seq(250.76653); check_primitive_seq(250.76653e40); +#ifdef WIN32 + check_primitive_seq(1.79e308l); +#else check_primitive_seq(250.76653e1000l); +#endif // WIN32 check_primitive_seq('L'); check_primitive_seq(L'G'); } diff --git a/test/unitary/xtypes/dynamicdata_operators.cpp b/test/unitary/xtypes/dynamicdata_operators.cpp index 924a1c38..bffa5f97 100644 --- a/test/unitary/xtypes/dynamicdata_operators.cpp +++ b/test/unitary/xtypes/dynamicdata_operators.cpp @@ -69,7 +69,7 @@ TEST (DynamicDataOperators, increment_decrement_operators) check_de_increment_operators(true, true); check_de_increment_operators('a', true); check_de_increment_operators('\n', true); - check_de_increment_operators(u'ñ', true); + check_de_increment_operators('\u00f1', true); check_de_increment_operators(PI, true); check_de_increment_operators(PI_D, true); check_de_increment_operators(PI_L, true); @@ -119,7 +119,7 @@ TEST (DynamicDataOperators, arithmetic_unary_operators) check_bitwise_complement_operator(true, true); check_bitwise_complement_operator('a', true); check_bitwise_complement_operator('\n', true); - check_bitwise_complement_operator(u'ñ', true); + check_bitwise_complement_operator('\u00f1', true); check_bitwise_complement_operator(7u, true); check_bitwise_complement_operator(10u, true); check_bitwise_complement_operator(20u, true); @@ -137,7 +137,7 @@ TEST (DynamicDataOperators, arithmetic_unary_operators) check_negate_operator(true, true); check_negate_operator('a', true); check_negate_operator('\n', true); - check_negate_operator(u'ñ', true); + check_negate_operator('\u00f1', true); check_negate_operator(7u, true); check_negate_operator(10u, true); check_negate_operator(20u, true); @@ -227,7 +227,7 @@ TEST (DynamicDataOperators, arithmetic_binary_operators) check_arithmetic_int_binary_operators(true, false, true); check_arithmetic_int_binary_operators('a', 'b', true); check_arithmetic_int_binary_operators('\n', 'b', true); - check_arithmetic_int_binary_operators(u'ñ', 'b', true); + check_arithmetic_int_binary_operators('\u00f1', 'b', true); // Operators available (only floating-point) check_arithmetic_flt_binary_operators(PI, 1.5f); check_arithmetic_flt_binary_operators(PI_D, 1.5); @@ -271,7 +271,7 @@ TEST (DynamicDataOperators, logical_operators) check_logical_not_operator(true); check_logical_not_operator('a'); check_logical_not_operator('\0'); - check_logical_not_operator(u'ñ'); + check_logical_not_operator('\u00f1'); check_logical_not_operator(1); check_logical_not_operator(1u); check_logical_not_operator(0); @@ -299,7 +299,7 @@ TEST (DynamicDataOperators, logical_operators) check_logical_binary_operator(true, false); check_logical_binary_operator('a', 'b'); check_logical_binary_operator('\n', '\0'); - check_logical_binary_operator(u'ñ', '\0'); + check_logical_binary_operator('\u00f1', '\0'); check_logical_binary_operator(1, -2); check_logical_binary_operator(1u, 2u); check_logical_binary_operator(4, 23); @@ -336,7 +336,7 @@ TEST (DynamicDataOperators, comparison_operators) check_comparison_binary_operator(true, false); check_comparison_binary_operator('a', 'b'); check_comparison_binary_operator('\n', '\0'); - check_comparison_binary_operator(u'ñ', '\0'); + check_comparison_binary_operator('\u00f1', '\0'); check_comparison_binary_operator(1, -2); check_comparison_binary_operator(1u, 2u); check_comparison_binary_operator(4, 23); @@ -450,7 +450,7 @@ TEST (DynamicDataOperators, assignment_operators) check_assignment_operators(true, false, true); check_assignment_operators('a', 'b', true); check_assignment_operators('\n', 'b', true); - check_assignment_operators(u'ñ', u'b', true); + check_assignment_operators('\u00f1', u'b', true); /* DynamicData a(primitive_type()); DynamicData b(primitive_type()); diff --git a/test/unitary/xtypes/no_memcheck_tests.cpp b/test/unitary/xtypes/no_memcheck_tests.cpp index 3d9a4689..266779e2 100644 --- a/test/unitary/xtypes/no_memcheck_tests.cpp +++ b/test/unitary/xtypes/no_memcheck_tests.cpp @@ -57,10 +57,18 @@ void assignCheck(A value) // Primitive long double fails when running on valgrind because valgrind uses 64bit to represent long double, // so the EXPECT_FALSE check fails. +// On windows long double == double TEST (PrimitiveTypes, primitive_type_longdouble) { + +#ifdef WIN32 + EXPECT_TRUE(singleCheck(1.797e308L, 1.797e308L)); + EXPECT_FALSE(singleCheck(1.7970000000000001e308L, 1.797e308L)); +#else EXPECT_TRUE(singleCheck(5.55e1200l, 5.55e1200l)); - EXPECT_FALSE(singleCheck(5.550000001e1200l, 5.55e1200l)); + EXPECT_FALSE(singleCheck(5.550000000000000001e1200l, 5.55e1200l)); +#endif // WIN32 + assignCheck(LDOUBLE); } diff --git a/test/unitary/xtypes/primitive_types.cpp b/test/unitary/xtypes/primitive_types.cpp index 141c372c..c7200fa3 100644 --- a/test/unitary/xtypes/primitive_types.cpp +++ b/test/unitary/xtypes/primitive_types.cpp @@ -29,7 +29,7 @@ static const uint64_t UINT64 = 18446744073709551610ULL; static const float FLOAT = 3.1415927410125732421875f; static const double DOUBLE = 3.1415926535897931159979631875; static const char CHAR = 'f'; -static const char16_t CHAR16 = u'ñ'; +static const char16_t CHAR16 = '\u00f1'; static const wchar_t WCHAR = 34590; /********************************************* diff --git a/test/unitary/xtypes/struct_type.cpp b/test/unitary/xtypes/struct_type.cpp index 843083a3..a51165fa 100644 --- a/test/unitary/xtypes/struct_type.cpp +++ b/test/unitary/xtypes/struct_type.cpp @@ -35,7 +35,7 @@ static const float FLOAT = 3.1415927410125732421875f; static const double DOUBLE = 3.1415926535897931159979631875; static const long double LDOUBLE = 3.14159265358979321159979631875l; static const char CHAR = 'f'; -static const char16_t CHAR16 = u'ñ'; +static const char16_t CHAR16 = '\u00f1'; static const wchar_t WCHAR = 34590; static const std::string INNER_STRING_VALUE = "lay_down_and_cry"; From ae117a5dc730087cfb03dc0c5489115c0744d758 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 20 Dec 2022 17:04:22 +0100 Subject: [PATCH 04/49] Refs 16497. Update peglib api. Signed-off-by: Miguel Barro --- include/xtypes/idl/parser.hpp | 126 ++++++++++++++-------------------- 1 file changed, 50 insertions(+), 76 deletions(-) diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 513f50bc..212f8f0c 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -42,6 +42,15 @@ #include #include +#ifdef _MSVC_LANG +# pragma push_macro("popen") +# define popen _popen +# pragma push_macro("pipe") +# define pipe _pipe +# pragma push_macro("pclose") +# define pclose _pclose +#endif + namespace peg { using Ast = AstBase; @@ -65,16 +74,16 @@ enum LogLevel struct LogEntry { std::string path; - uint32_t line; - uint32_t column; + size_t line; + size_t column; LogLevel level; std::string category; std::string message; LogEntry( const std::string& file, - uint32_t line_number, - uint32_t column_number, + size_t line_number, + size_t column_number, LogLevel log_level, const std::string& cat, const std::string& msg) @@ -310,18 +319,15 @@ class Parser context.instance_ = this; context_ = &context; std::shared_ptr ast; - std::string idl_to_parse = idl_string; - if (context.preprocess) - { - idl_to_parse = preprocess_string(idl_to_parse); - } - if (!parser_.parse(idl_to_parse.c_str(), ast)) + + if (!parser_.parse(idl_string.c_str(), ast)) { context.success = false; context_->log(log::LogLevel::DEBUG, "RESULT", "The parser found errors while parsing."); return false; } + ast = parser_.optimize_ast(ast); build_on_ast(ast); context.module_ = root_scope_; @@ -339,37 +345,45 @@ class Parser return context; } + Context parse_string( + const std::string& idl_string) + { + Context context = DEFAULT_CONTEXT; + parse_string(idl_string, context); + return context; + } + bool parse_file( const std::string& idl_file, Context& context) { context.instance_ = this; context_ = &context; - std::vector source; std::shared_ptr ast; if (context.preprocess) { std::string file_content = preprocess_file(idl_file); return parse(file_content, context); } + + std::ostringstream os; + os << std::ifstream(idl_file).rdbuf(); + return parse(os.str(), context); + } + + bool parse_string( + const std::string& idl_string, + Context& context) + { + context.instance_ = this; + + if (context.preprocess) + { + return parse(preprocess_string(idl_string), context); + } else { - if (!(read_file(idl_file.c_str(), source) - && parser_.parse_n(source.data(), source.size(), ast, idl_file.c_str()))) - { - context.success = false; - context_->log(log::LogLevel::DEBUG, "RESULT", - "The parser found errors while parsing."); - return false; - } - - ast = parser_.optimize_ast(ast); - build_on_ast(ast); - context.module_ = root_scope_; - context.success = true; - context_->log(log::LogLevel::DEBUG, "RESULT", - "The parser finished."); - return true; + return parse(idl_string, context); } } @@ -455,30 +469,6 @@ class Parser l - CPP_PEGLIB_LINE_COUNT_ERROR) + ":" + std::to_string(c) + ")"); } - bool read_file( - const char* path, - std::vector& buff) const - { - std::ifstream ifs(path, std::ios::in | std::ios::binary); - - if (ifs.fail()) - { - context_->log(log::LogLevel::DEBUG, "FILE", - "Cannot open file: " + std::string(path)); - return false; - } - - buff.resize(static_cast(ifs.seekg(0, std::ios::end).tellg())); - - if (!buff.empty()) - { - ifs.seekg(0, std::ios::beg).read(&buff[0], static_cast(buff.size())); - } - context_->log(log::LogLevel::DEBUG, "FILE", - "Loaded file: " + std::string(path)); - return true; - } - static std::string exec( const std::string& cmd, bool filter_stderr = true) @@ -521,7 +511,7 @@ class Parser str.replace(pos, froms, escaped); pos = str.find(from, pos + escaped_size); } - + } } @@ -634,7 +624,7 @@ class Parser return std::string(identifier.substr(1).data(), identifier.substr(1).size()); // If the identifier starts with "_", remove the underscode and return. } - if (is_token(identifier)) + if (ast->is_token) { std::stringstream message; message << "The identifier \"" << identifier << "\" is a reserved word."; @@ -673,29 +663,6 @@ class Parser }); } - bool is_token( - const std::string_view& identifier) - { - std::string aux_id(identifier.data(), identifier.size()); - - if (context_->ignore_case) - { - to_lower(aux_id); - } - - for (const std::string& name : parser_.get_rule_names()) - { - if (name.find("KW_") == 0) // If it starts with "KW_", is a reserved word. You are welcome. - { - if (parser_[name.c_str()].parse(aux_id.c_str()).ret) - { - return true; - } - } - } - return false; - } - void module_dcl( const std::shared_ptr& ast, std::shared_ptr& outer) @@ -2076,4 +2043,11 @@ void Context::clear_context() } // namespace xtypes } // namespace eprosima + +#ifdef _MSVC_LANG +# pragma pop_macro("popen") +# pragma pop_macro("pipe") +# pragma pop_macro("pclose") +#endif + #endif // EPROSIMA_XTYPES_IDL_PARSER_HPP_ From 2140440b919c169b66ea2a2314e7e6db8931135d Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Wed, 21 Dec 2022 12:57:15 +0100 Subject: [PATCH 05/49] Refs 16497. Preprocessor strategy refactored Signed-off-by: Miguel Barro --- CMakeLists.txt | 14 +- include/xtypes/idl/idl.hpp | 2 +- include/xtypes/idl/parser.hpp | 281 +++++++++++++++++++++------------- 3 files changed, 190 insertions(+), 107 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 521f8484..318b2c80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,11 +94,19 @@ find_program(NODERED_EXECUTABLE NAMES node-red node-red@ PATH_SUFFIXES bin) if(XTYPES_BUILD_TOOLS OR NODERED_EXECUTABLE) compile_tool(xtypes_idl_validator SOURCE tools/idl_validator.cpp) + # WSL for example lacks TMP + if(NOT ENV{TMP}) + set(TMP_ROOT "/tmp") + else() + set(TMP_ROOT "$ENV{TMP}") + endif() + if (NODERED_EXECUTABLE) - file(WRITE $ENV{TMP}/idl_parser_path.txt "${PROJECT_BINARY_DIR}") + file(WRITE ${TMP_ROOT}/idl_parser_path.txt "${PROJECT_BINARY_DIR}") message("${PROJECT_BINARY_DIR}") endif() - # ... + + unset(TMP_ROOT) endif() ##################################################################################### @@ -126,7 +134,7 @@ macro(compile_example) target_compile_options(${EXAMPLE_NAME} INTERFACE - $<$:-Wall -Wextra> + $<$:-Wall -Wextra -Wno-multichar> ) endmacro() diff --git a/include/xtypes/idl/idl.hpp b/include/xtypes/idl/idl.hpp index 303d1941..fe5b58b5 100644 --- a/include/xtypes/idl/idl.hpp +++ b/include/xtypes/idl/idl.hpp @@ -74,7 +74,7 @@ inline std::string preprocess( const std::string& idl_file, const std::vector& includes) { - return Parser::preprocess("cpp", idl_file, includes); + return Parser::preprocess(idl_file, includes); } /// \brief Generates the IDL that represents an StructType diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 212f8f0c..64d3cfbb 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -42,7 +43,8 @@ #include #include -#ifdef _MSVC_LANG +// mimic posix pipe APIs +#ifdef _MSC_VER # pragma push_macro("popen") # define popen _popen # pragma push_macro("pipe") @@ -51,6 +53,19 @@ # define pclose _pclose #endif +// define preprocessor strategy +#ifdef _MSC_VER +# define EPROSIMA_PLATFORM_PREPROCESSOR "cl /EP" +# define EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY preprocess_strategy::temporary_file +# define EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES "/I" +# define EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR " 2> nul" +#else +# define EPROSIMA_PLATFORM_PREPROCESSOR "cpp -H" +# define EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY preprocess_strategy::pipe_stdin +# define EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES "-I " +# define EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR " 2> /dev/null" +#endif + namespace peg { using Ast = AstBase; @@ -135,8 +150,9 @@ struct LogEntry class Parser; -struct Context +class Context { +public: enum CharType { CHAR, @@ -150,15 +166,26 @@ struct Context CHAR16_T }; + // Preprocessors capability to use shared memory (pipes) or stick to file input + enum class preprocess_strategy + { + pipe_stdin, + temporary_file + }; + // Config bool ignore_case = false; bool clear = true; - bool preprocess = true; bool allow_keyword_identifiers = false; bool ignore_redefinition = false; CharType char_translation = CHAR; WideCharType wchar_type = WCHAR_T; - std::string preprocessor_exec = "cpp"; + + bool preprocess = true; + std::string preprocessor_exec = EPROSIMA_PLATFORM_PREPROCESSOR; + std::string error_redir = EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR; + preprocess_strategy strategy = EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY; + std::string include_flag = EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES; std::vector include_paths; // Results @@ -228,23 +255,33 @@ struct Context print_log_ = enable; } -private: + std::string preprocess_file( + const std::string& idl_file) const + { + std::vector includes; + std::string args; + for (const std::string inc_path : include_paths) + { + args += include_flag + inc_path + " "; + } - friend class Parser; - Parser* instance_; - std::shared_ptr module_ = nullptr; - std::vector log_; - log::LogLevel log_level_ = log::LogLevel::WARNING; - bool print_log_ = false; + std::string cmd = preprocessor_exec + " " + args + idl_file + error_redir; - inline void clear_context(); + log(log::LogLevel::DEBUG, "PREPROCESS", + "Calling preprocessor with command: " + cmd); + std::string output = exec(cmd); + return output; + } + + std::string preprocess_string( + const std::string& idl_string) const; // Logging void log( log::LogLevel level, const std::string& category, const std::string& message, - std::shared_ptr ast = nullptr) + std::shared_ptr ast = nullptr) const { if (log_level_ >= level) { @@ -264,10 +301,133 @@ struct Context } } +private: + + friend class Parser; + Parser* instance_; + std::shared_ptr module_ = nullptr; + mutable std::vector log_; + log::LogLevel log_level_ = log::LogLevel::WARNING; + bool print_log_ = false; + + inline void clear_context(); + + template + std::string preprocess_string( + const std::string& idl_string) const; + + static std::string exec( + const std::string& cmd) + { + std::unique_ptr pipe(popen(cmd.c_str(), "rt"), pclose); + if (!pipe) + { + throw std::runtime_error("popen() failed!"); + } + +#ifdef _MSC_VER + std::filebuf buff(pipe.get()); + std::ostringstream os; + os << &buff; + return os.str(); +#else + std::array buffer; + std::string result; + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) + { + result += buffer.data(); + } + return result; +#endif // _MSC_VER + } + + void replace_all_string( + std::string& str, + const std::string& from, + const std::string& to) const + { + size_t froms = from.size(); + size_t tos = to.size(); + size_t pos = str.find(from); + const std::string escaped = "\\\\\""; + size_t escaped_size = escaped.size(); + while (pos != std::string::npos) + { + str.replace(pos, froms, to); + pos = str.find(from, pos + tos); + while (str[pos - 1] == '\\') + { + str.replace(pos, froms, escaped); + pos = str.find(from, pos + escaped_size); + } + + } + } + }; static const Context DEFAULT_CONTEXT = Context(); +template<> +std::string Context::preprocess_string( + const std::string& idl_string) const +{ + std::string args; + for (const std::string inc_path : include_paths) + { + args += include_flag + inc_path + " "; + } + // Escape double quotes inside the idl_string + std::string escaped_idl_string = idl_string; + replace_all_string(escaped_idl_string, "\"", "\\\""); + std::string cmd = "echo \"" + escaped_idl_string + "\" | " + + preprocessor_exec + " " + args + error_redir; + + log(log::LogLevel::DEBUG, "PREPROCESS", + "Calling preprocessor '" + preprocessor_exec + "' for an IDL string."); + + return exec(cmd); +} + +template<> +std::string Context::preprocess_string( + const std::string& idl_string) const +{ + static std::hash fn; + + // Create temporary filename + auto tmp = std::filesystem::temp_directory_path(); + tmp /= "xtypes_"; + tmp += fn(idl_string); + + { // Populate + std::ofstream os(tmp); + os << idl_string; + } + + auto processed = preprocess_file(tmp.string()); + + // dispose + std::filesystem::remove(tmp); + + return processed; +} + +std::string Context::preprocess_string( + const std::string& idl_string) const +{ + switch(strategy) + { + case Context::preprocess_strategy::pipe_stdin: + return preprocess_string(idl_string); + case Context::preprocess_strategy::temporary_file: + return preprocess_string(idl_string); + } + + throw std::range_error("unknown preprocessor strategy selected."); + return ""; +} + class Parser { public: @@ -362,7 +522,7 @@ class Parser std::shared_ptr ast; if (context.preprocess) { - std::string file_content = preprocess_file(idl_file); + std::string file_content = context.preprocess_file(idl_file); return parse(file_content, context); } @@ -379,7 +539,7 @@ class Parser if (context.preprocess) { - return parse(preprocess_string(idl_string), context); + return parse(context.preprocess_string(idl_string), context); } else { @@ -430,18 +590,12 @@ class Parser }; static std::string preprocess( - const std::string& preprocessor_path, const std::string& idl_file, const std::vector& includes) { - std::string args = "-H "; - for (const std::string inc_path : includes) - { - args += "-I " + inc_path + " "; - } - std::string cmd = preprocessor_path + " " + args + idl_file; - std::string output = exec(cmd); - return output; + Context ctx = DEFAULT_CONTEXT; + ctx.include_paths = includes; + return ctx.preprocess_file(idl_file); } private: @@ -469,85 +623,6 @@ class Parser l - CPP_PEGLIB_LINE_COUNT_ERROR) + ":" + std::to_string(c) + ")"); } - static std::string exec( - const std::string& cmd, - bool filter_stderr = true) - { - std::array buffer; - std::string command = cmd; - if (filter_stderr) - { - command.append(" 2> /dev/null"); - } - std::string result; - std::unique_ptr pipe(popen(command.c_str(), "r"), pclose); - if (!pipe) - { - throw std::runtime_error("popen() failed!"); - } - while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) - { - result += buffer.data(); - } - return result; - } - - void replace_all_string( - std::string& str, - const std::string& from, - const std::string& to) const - { - size_t froms = from.size(); - size_t tos = to.size(); - size_t pos = str.find(from); - const std::string escaped = "\\\\\""; - size_t escaped_size = escaped.size(); - while (pos != std::string::npos) - { - str.replace(pos, froms, to); - pos = str.find(from, pos + tos); - while (str[pos - 1] == '\\') - { - str.replace(pos, froms, escaped); - pos = str.find(from, pos + escaped_size); - } - - } - } - - std::string preprocess_string( - const std::string& idl_string) const - { - std::string args = "-H "; - for (const std::string inc_path : context_->include_paths) - { - args += "-I " + inc_path + " "; - } - // Escape double quotes inside the idl_string - std::string escaped_idl_string = idl_string; - replace_all_string(escaped_idl_string, "\"", "\\\""); - std::string cmd = "echo \"" + escaped_idl_string + "\" | " + context_->preprocessor_exec + " " + args; - context_->log(log::LogLevel::DEBUG, "PREPROCESS", - "Calling preprocessor '" + context_->preprocessor_exec + "' for an IDL string."); - return exec(cmd); - } - - std::string preprocess_file( - const std::string& idl_file) - { - std::vector includes; - std::string args = "-H "; - for (const std::string inc_path : context_->include_paths) - { - args += "-I " + inc_path + " "; - } - std::string cmd = context_->preprocessor_exec + " " + args + idl_file; - context_->log(log::LogLevel::DEBUG, "PREPROCESS", - "Calling preprocessor with command: " + cmd); - std::string output = exec(cmd); - return output; - } - std::shared_ptr build_on_ast( const std::shared_ptr& ast, std::shared_ptr scope = nullptr) From 5aa3020b1791ec4b642010c8b83452dd5b46f960 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Wed, 21 Dec 2022 17:47:15 +0100 Subject: [PATCH 06/49] Refs 16497. Fixing gtest on windows Signed-off-by: Miguel Barro --- CMakeLists.txt | 26 +- include/xtypes/DynamicData.hpp | 3 + include/xtypes/DynamicDataImpl.hpp | 30 +- include/xtypes/Instanceable.hpp | 12 +- include/xtypes/idl/generator_deptree.hpp | 4 +- include/xtypes/idl/parser.hpp | 314 +++++++++--------- test/gtest.cmake | 26 -- test/unitary/generator/dependencies.cpp | 2 - test/unitary/xtypes/alias_type.cpp | 2 +- test/unitary/xtypes/dynamicdata_operators.cpp | 135 +++++++- test/unitary/xtypes/primitive_types.cpp | 2 +- 11 files changed, 347 insertions(+), 209 deletions(-) delete mode 100644 test/gtest.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 318b2c80..df91f658 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,14 +29,14 @@ endif() # Download the cpp-peglib header file needed file(DOWNLOAD https://raw.githubusercontent.com/yhirose/cpp-peglib/master/peglib.h - ${PROJECT_SOURCE_DIR}/thirdparty/cpp-peglib/peglib.h + ${PROJECT_BINARY_DIR}/thirdparty/cpp-peglib/peglib.h ) # MSVC always returns __cplusplus = 199711 unles we use the flag /Zc:__cplusplus then it follows the GNU behavior if(MSVC) execute_process(COMMAND - powershell -Command [=[ - $header = gi thirdparty/cpp-peglib/peglib.h; + powershell -Command "$binarydir = \"${PROJECT_BINARY_DIR}\";" [=[ + $header = gi "$binarydir/thirdparty/cpp-peglib/peglib.h"; (cat $header | % { $_ -replace '__cplusplus', '_MSVC_LANG' } ) | Set-Content $header ]=] WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} @@ -46,7 +46,7 @@ endif(MSVC) target_include_directories(xtypes INTERFACE $ - $ + $ $ $ ) @@ -84,7 +84,7 @@ macro(compile_tool) ) target_compile_options(${TOOL_NAME} - INTERFACE + PRIVATE $<$:-Wall -Wextra> ) endmacro() @@ -133,8 +133,8 @@ macro(compile_example) ) target_compile_options(${EXAMPLE_NAME} - INTERFACE - $<$:-Wall -Wextra -Wno-multichar> + PRIVATE + $<$:-Wall -Wextra -Wno-sign-compare -Wno-multichar> ) endmacro() @@ -163,7 +163,7 @@ macro(compile_test) target_link_libraries(${TEST_NAME} PRIVATE - libgtest + GTest::gtest ) add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) @@ -171,9 +171,11 @@ endmacro() if(XTYPES_BUILD_TESTS) include(CTest) - include(test/gtest.cmake) enable_testing() + # apt install libgtest-dev + find_package(GTest CONFIG REQUIRED) + compile_test(xtypes_test_unitary SOURCE test/unitary/xtypes/main.cpp test/unitary/xtypes/primitive_types.cpp @@ -279,7 +281,7 @@ install( install( DIRECTORY - ${PROJECT_SOURCE_DIR}/thirdparty/cpp-peglib/ + ${PROJECT_BINARY_DIR}/thirdparty/cpp-peglib/ DESTINATION thirdparty/cpp-peglib/include FILES_MATCHING @@ -289,8 +291,8 @@ install( install( EXPORT xtypes-targets - NAMESPACE - eprosima +# NAMESPACE +# eprosima:: DESTINATION ${DATA_INSTALL_DIR}/xtypes/cmake ) diff --git a/include/xtypes/DynamicData.hpp b/include/xtypes/DynamicData.hpp index 2e36793a..751101b4 100644 --- a/include/xtypes/DynamicData.hpp +++ b/include/xtypes/DynamicData.hpp @@ -780,6 +780,9 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef { public: + WritableDynamicDataRef(const WritableDynamicDataRef&) = default; + WritableDynamicDataRef(WritableDynamicDataRef&&) = default; + using ReadableDynamicDataRef::operator []; using ReadableDynamicDataRef::value; using ReadableDynamicDataRef::d; diff --git a/include/xtypes/DynamicDataImpl.hpp b/include/xtypes/DynamicDataImpl.hpp index 61c92054..43967914 100644 --- a/include/xtypes/DynamicDataImpl.hpp +++ b/include/xtypes/DynamicDataImpl.hpp @@ -57,8 +57,9 @@ namespace xtypes { MACRO(uint32_t, OPERATOR);\ case TypeKind::UINT_64_TYPE:\ MACRO(uint64_t, OPERATOR);\ + default:\ + DYNAMIC_DATA_NUMERIC_SIGNED_INT_SWITCH(MACRO, OPERATOR);\ }\ - DYNAMIC_DATA_NUMERIC_SIGNED_INT_SWITCH(MACRO, OPERATOR);\ } #define DYNAMIC_DATA_NUMERIC_FLT_SWITCH(MACRO, OPERATOR) \ @@ -71,6 +72,8 @@ namespace xtypes { MACRO(double, OPERATOR);\ case TypeKind::FLOAT_128_TYPE:\ MACRO(long double, OPERATOR);\ + default:\ + return *this;\ }\ } @@ -98,8 +101,9 @@ namespace xtypes { MACRO(wchar_t, OPERATOR);\ case TypeKind::BOOLEAN_TYPE:\ MACRO(bool, OPERATOR);\ + default:\ + DYNAMIC_DATA_NUMERIC_SWITCH(MACRO, OPERATOR);\ }\ - DYNAMIC_DATA_NUMERIC_SWITCH(MACRO, OPERATOR);\ } #define DYNAMIC_DATA_BASICTYPE_INT_SWITCH(MACRO, OPERATOR) \ @@ -114,8 +118,9 @@ namespace xtypes { MACRO(wchar_t, OPERATOR);\ case TypeKind::BOOLEAN_TYPE:\ MACRO(bool, OPERATOR);\ + default:\ + DYNAMIC_DATA_NUMERIC_INT_SWITCH(MACRO, OPERATOR);\ }\ - DYNAMIC_DATA_NUMERIC_INT_SWITCH(MACRO, OPERATOR);\ } inline std::string ReadableDynamicDataRef::to_string() const @@ -264,12 +269,19 @@ inline std::string ReadableDynamicDataRef::cast() const uint32_t temp = *this; return std::to_string(temp); } + else + { + xtypes_assert(false, "invalid enum size") + return ""; + } } case TypeKind::STRING_TYPE: { std::string temp = *this; return temp; } + default: + DYNAMIC_DATA_BASICTYPE_SWITCH(DYNAMIC_DATA_CAST, ); /* // TODO case TypeKind::WSTRING_TYPE: { @@ -283,7 +295,6 @@ inline std::string ReadableDynamicDataRef::cast() const } */ } - DYNAMIC_DATA_BASICTYPE_SWITCH(DYNAMIC_DATA_CAST, ); return std::string(); } @@ -350,8 +361,9 @@ inline bool DynamicData::operator ! () const return this->value().empty(); case TypeKind::STRING16_TYPE: return this->value().empty(); + default: + DYNAMIC_DATA_BASICTYPE_INT_SWITCH(DYNAMIC_DATA_NOT_OPERATOR_RESULT, !); } - DYNAMIC_DATA_BASICTYPE_INT_SWITCH(DYNAMIC_DATA_NOT_OPERATOR_RESULT, !); } #define DYNAMIC_DATA_LOGIC_OPERATION(TYPE, OPERATOR) \ @@ -461,6 +473,14 @@ template \ DYNAMIC_DATA_SELF_ASSIGN_OPERATOR_IMPLEMENTATION(*); +// Specialize for bool to avoid warning -Wint-in-bool-context +template<> +inline DynamicData& DynamicData::operator *=(const bool& other) +{ + using T = bool; + DYNAMIC_DATA_PRIMITIVE_SELF_ASSIGN_OPERATOR_RESULT(&&); +} + DYNAMIC_DATA_SELF_ASSIGN_OPERATOR_IMPLEMENTATION(/); DYNAMIC_DATA_SELF_ASSIGN_OPERATOR_IMPLEMENTATION(%); diff --git a/include/xtypes/Instanceable.hpp b/include/xtypes/Instanceable.hpp index 3d0a7dcf..6cf05f36 100644 --- a/include/xtypes/Instanceable.hpp +++ b/include/xtypes/Instanceable.hpp @@ -167,12 +167,12 @@ class Instanceable switch (len & 7) { - case 7: v ^= static_cast(pos2[6]) << 48; - case 6: v ^= static_cast(pos2[5]) << 40; - case 5: v ^= static_cast(pos2[4]) << 32; - case 4: v ^= static_cast(pos2[3]) << 24; - case 3: v ^= static_cast(pos2[2]) << 16; - case 2: v ^= static_cast(pos2[1]) << 8; + case 7: v ^= static_cast(pos2[6]) << 48; [[fallthrough]]; + case 6: v ^= static_cast(pos2[5]) << 40; [[fallthrough]]; + case 5: v ^= static_cast(pos2[4]) << 32; [[fallthrough]]; + case 4: v ^= static_cast(pos2[3]) << 24; [[fallthrough]]; + case 3: v ^= static_cast(pos2[2]) << 16; [[fallthrough]]; + case 2: v ^= static_cast(pos2[1]) << 8; [[fallthrough]]; case 1: v ^= static_cast(pos2[0]); h ^= mix(v); h *= m; diff --git a/include/xtypes/idl/generator_deptree.hpp b/include/xtypes/idl/generator_deptree.hpp index e9f6b0a0..3f0f4e36 100644 --- a/include/xtypes/idl/generator_deptree.hpp +++ b/include/xtypes/idl/generator_deptree.hpp @@ -389,10 +389,10 @@ class DependencyModule const std::shared_ptr& d_root, const Module& module, DependencyModule* outer) - : module_(module) + : iterated_(false) + , module_(module) , d_root_(d_root) , d_outer_(outer) - ,iterated_(false) {} /// \brief Check out if this DependencyModule has already been iterated. diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 64d3cfbb..3f675635 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -41,6 +41,7 @@ #include #include #include +#include #include // mimic posix pipe APIs @@ -148,76 +149,14 @@ struct LogEntry } // namespace log -class Parser; - -class Context +class LogContext { -public: - enum CharType - { - CHAR, - UINT8, - INT8 - }; - - enum WideCharType - { - WCHAR_T, - CHAR16_T - }; - - // Preprocessors capability to use shared memory (pipes) or stick to file input - enum class preprocess_strategy - { - pipe_stdin, - temporary_file - }; - - // Config - bool ignore_case = false; - bool clear = true; - bool allow_keyword_identifiers = false; - bool ignore_redefinition = false; - CharType char_translation = CHAR; - WideCharType wchar_type = WCHAR_T; - - bool preprocess = true; - std::string preprocessor_exec = EPROSIMA_PLATFORM_PREPROCESSOR; - std::string error_redir = EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR; - preprocess_strategy strategy = EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY; - std::string include_flag = EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES; - std::vector include_paths; - - // Results - bool success = false; - - std::map get_all_types( - bool scope = false) - { - std::map result; - if (module_ != nullptr) - { - module_->fill_all_types(result, scope); - } - return result; - } - - std::map get_all_scoped_types() - { - return get_all_types(true); - } - - Module& module() - { - return *module_; - } + mutable std::vector log_; + log::LogLevel log_level_ = log::LogLevel::WARNING; + bool print_log_ = false; - ~Context() - { - clear_context(); - } +public: - // Logging const std::vector& log() const { return log_; @@ -255,27 +194,6 @@ class Context print_log_ = enable; } - std::string preprocess_file( - const std::string& idl_file) const - { - std::vector includes; - std::string args; - for (const std::string inc_path : include_paths) - { - args += include_flag + inc_path + " "; - } - - std::string cmd = preprocessor_exec + " " + args + idl_file + error_redir; - - log(log::LogLevel::DEBUG, "PREPROCESS", - "Calling preprocessor with command: " + cmd); - std::string output = exec(cmd); - return output; - } - - std::string preprocess_string( - const std::string& idl_string) const; - // Logging void log( log::LogLevel level, @@ -300,24 +218,109 @@ class Context } } } +}; -private: +class PreprocessorContext + : public LogContext +{ +public: - friend class Parser; - Parser* instance_; - std::shared_ptr module_ = nullptr; - mutable std::vector log_; - log::LogLevel log_level_ = log::LogLevel::WARNING; - bool print_log_ = false; + // Preprocessors capability to use shared memory (pipes) or stick to file input + enum class preprocess_strategy + { + pipe_stdin, + temporary_file + }; - inline void clear_context(); + bool preprocess = true; + std::string preprocessor_exec = EPROSIMA_PLATFORM_PREPROCESSOR; + std::string error_redir = EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR; + preprocess_strategy strategy = EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY; + std::string include_flag = EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES; + std::vector include_paths; + + std::string preprocess_file( + const std::string& idl_file) const + { + std::vector includes; + std::string args; + for (const std::string& inc_path : include_paths) + { + args += include_flag + inc_path + " "; + } + + std::string cmd = preprocessor_exec + " " + args + idl_file + error_redir; + + log(log::LogLevel::DEBUG, "PREPROCESS", + "Calling preprocessor with command: " + cmd); + std::string output = exec(cmd); + return output; + } + + // preprocessing using pipes + std::string preprocess_string( + const std::string& idl_string, + std::true_type) const + { + std::string args; + for (const std::string& inc_path : include_paths) + { + args += include_flag + inc_path + " "; + } + // Escape double quotes inside the idl_string + std::string escaped_idl_string = idl_string; + replace_all_string(escaped_idl_string, "\"", "\\\""); + std::string cmd = "echo \"" + escaped_idl_string + "\" | " + + preprocessor_exec + " " + args + error_redir; + + log(log::LogLevel::DEBUG, "PREPROCESS", + "Calling preprocessor '" + preprocessor_exec + "' for an IDL string."); + + return exec(cmd); + } + + // preprocessing using files + std::string preprocess_string( + const std::string& idl_string, + std::false_type) const + { + static std::hash fn; + + // Create temporary filename + auto tmp = std::filesystem::temp_directory_path(); + tmp /= "xtypes_"; + tmp += fn(idl_string); + + { // Populate + std::ofstream os(tmp); + os << idl_string; + } + + auto processed = preprocess_file(tmp.string()); + + // dispose + std::filesystem::remove(tmp); + + return processed; + } - template std::string preprocess_string( - const std::string& idl_string) const; + const std::string& idl_string) const + { + switch(strategy) + { + case preprocess_strategy::pipe_stdin: + return preprocess_string(idl_string, std::true_type()); + case preprocess_strategy::temporary_file: + return preprocess_string(idl_string, std::false_type()); + } + + xtypes_assert(true, "unknown preprocessor strategy selected.") + return ""; + } - static std::string exec( - const std::string& cmd) + std::string exec( + const std::string& cmd) const { std::unique_ptr pipe(popen(cmd.c_str(), "rt"), pclose); if (!pipe) @@ -325,12 +328,12 @@ class Context throw std::runtime_error("popen() failed!"); } -#ifdef _MSC_VER + #ifdef _MSC_VER std::filebuf buff(pipe.get()); std::ostringstream os; os << &buff; return os.str(); -#else + #else std::array buffer; std::string result; while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) @@ -338,7 +341,7 @@ class Context result += buffer.data(); } return result; -#endif // _MSC_VER + #endif // _MSC_VER } void replace_all_string( @@ -363,70 +366,74 @@ class Context } } - }; -static const Context DEFAULT_CONTEXT = Context(); +class Parser; -template<> -std::string Context::preprocess_string( - const std::string& idl_string) const +class Context + : public PreprocessorContext { - std::string args; - for (const std::string inc_path : include_paths) +public: + enum CharType { - args += include_flag + inc_path + " "; - } - // Escape double quotes inside the idl_string - std::string escaped_idl_string = idl_string; - replace_all_string(escaped_idl_string, "\"", "\\\""); - std::string cmd = "echo \"" + escaped_idl_string + "\" | " - + preprocessor_exec + " " + args + error_redir; - - log(log::LogLevel::DEBUG, "PREPROCESS", - "Calling preprocessor '" + preprocessor_exec + "' for an IDL string."); + CHAR, + UINT8, + INT8 + }; - return exec(cmd); -} + enum WideCharType + { + WCHAR_T, + CHAR16_T + }; -template<> -std::string Context::preprocess_string( - const std::string& idl_string) const -{ - static std::hash fn; + // Config + bool ignore_case = false; + bool clear = true; + bool allow_keyword_identifiers = false; + bool ignore_redefinition = false; + CharType char_translation = CHAR; + WideCharType wchar_type = WCHAR_T; - // Create temporary filename - auto tmp = std::filesystem::temp_directory_path(); - tmp /= "xtypes_"; - tmp += fn(idl_string); + // Results + bool success = false; - { // Populate - std::ofstream os(tmp); - os << idl_string; + std::map get_all_types( + bool scope = false) + { + std::map result; + if (module_ != nullptr) + { + module_->fill_all_types(result, scope); + } + return result; } - auto processed = preprocess_file(tmp.string()); - - // dispose - std::filesystem::remove(tmp); + std::map get_all_scoped_types() + { + return get_all_types(true); + } - return processed; -} + Module& module() + { + return *module_; + } -std::string Context::preprocess_string( - const std::string& idl_string) const -{ - switch(strategy) + ~Context() { - case Context::preprocess_strategy::pipe_stdin: - return preprocess_string(idl_string); - case Context::preprocess_strategy::temporary_file: - return preprocess_string(idl_string); + clear_context(); } - throw std::range_error("unknown preprocessor strategy selected."); - return ""; -} +private: + + friend class Parser; + Parser* instance_; + std::shared_ptr module_ = nullptr; + inline void clear_context(); + +}; + +static const Context DEFAULT_CONTEXT = Context(); class Parser { @@ -1461,7 +1468,7 @@ class Parser const std::shared_ptr& ast, std::shared_ptr& outer, std::vector& member_list, - const DynamicType::Ptr type) + const DynamicType::Ptr) { using namespace peg::udl; std::vector labels; @@ -1775,6 +1782,9 @@ class Parser return primitive_type(); case Context::INT8: return primitive_type(); + default: + xtypes_assert(false, "invalid char type") + return primitive_type(); } } case "WIDE_CHAR_TYPE"_: diff --git a/test/gtest.cmake b/test/gtest.cmake deleted file mode 100644 index 75a5f4b3..00000000 --- a/test/gtest.cmake +++ /dev/null @@ -1,26 +0,0 @@ -##################################################################################### -# GTest dependency as cmake external project -##################################################################################### - -find_package(Threads REQUIRED) - -include(ExternalProject) - -ExternalProject_Add(gtest - URL https://github.com/google/googletest/archive/master.zip - PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest - INSTALL_COMMAND "" - ) - -ExternalProject_Get_Property(gtest source_dir binary_dir) - -add_library(libgtest IMPORTED STATIC GLOBAL) -add_dependencies(libgtest gtest) - -set_target_properties(libgtest - PROPERTIES - "IMPORTED_LOCATION" "${binary_dir}/lib/libgtest.a" - "IMPORTED_LINK_INTERFACE_LIBRARIES" "${CMAKE_THREAD_LIBS_INIT}" - ) - -include_directories("${source_dir}/googletest/include") diff --git a/test/unitary/generator/dependencies.cpp b/test/unitary/generator/dependencies.cpp index 75409387..7da76cca 100644 --- a/test/unitary/generator/dependencies.cpp +++ b/test/unitary/generator/dependencies.cpp @@ -232,9 +232,7 @@ void generation_ambiguity_resolution_check( { const idl::Module& mod_A = root["A"]; const idl::Module& mod_B = root["B"]; - const idl::Module& mod_AB = mod_A["B"]; const idl::Module& mod_AC = mod_A["C"]; - const idl::Module& mod_ABA = mod_AB["A"]; // Retrieve all "MyStruct" types ASSERT_TRUE(root.has_structure("MyStruct")); diff --git a/test/unitary/xtypes/alias_type.cpp b/test/unitary/xtypes/alias_type.cpp index e6d8b7c7..ab26c43f 100644 --- a/test/unitary/xtypes/alias_type.cpp +++ b/test/unitary/xtypes/alias_type.cpp @@ -37,7 +37,7 @@ TEST (AliasType, alias_casting) { AliasType at(StringType(100), "str100"); - ASSERT_OR_EXCEPTION({ static_cast(at); }, + ASSERT_OR_EXCEPTION({ (void)static_cast(at); }, "cannot be cast to the specified type"); } diff --git a/test/unitary/xtypes/dynamicdata_operators.cpp b/test/unitary/xtypes/dynamicdata_operators.cpp index bffa5f97..b0756785 100644 --- a/test/unitary/xtypes/dynamicdata_operators.cpp +++ b/test/unitary/xtypes/dynamicdata_operators.cpp @@ -75,7 +75,12 @@ TEST (DynamicDataOperators, increment_decrement_operators) check_de_increment_operators(PI_L, true); } -#define CHECK_ARITHMETIC_UNARY_OPERATOR(value, assert_fail, OP) \ +#define GET_MACRO4(_1, _2, _3, _4, NAME, ...) NAME +#define CHECK_ARITHMETIC_UNARY_OPERATOR(...) \ + GET_MACRO4(__VA_ARGS__, CHECK_ARITHMETIC_UNARY_OPERATOR_COMPARE, \ + CHECK_ARITHMETIC_UNARY_OPERATOR_EXECUTE_OP)(__VA_ARGS__) + +#define CHECK_ARITHMETIC_UNARY_OPERATOR_EXECUTE_OP(value, assert_fail, OP) \ {\ const DynamicType& type(primitive_type());\ DynamicData data(type);\ @@ -92,6 +97,23 @@ TEST (DynamicDataOperators, increment_decrement_operators) }\ } +#define CHECK_ARITHMETIC_UNARY_OPERATOR_COMPARE(value, assert_fail, OP, result) \ +{\ + const DynamicType& type(primitive_type());\ + DynamicData data(type);\ + data = static_cast(value);\ +\ + if (assert_fail)\ + {\ + ASSERT_OR_EXCEPTION({ ASSERT_EQ_DYNAMICDATA(OP(data), (result)); },\ + std::string("Operator") + #OP + "()");\ + }\ + else\ + {\ + ASSERT_EQ_DYNAMICDATA(OP(data), (result));\ + }\ +} + template inline void check_bitwise_complement_operator( const T& value, @@ -100,6 +122,16 @@ inline void check_bitwise_complement_operator( CHECK_ARITHMETIC_UNARY_OPERATOR(value, assert_fail, ~); } +// in order to avoid warning C4804: ~value == !value +template<> +inline void check_bitwise_complement_operator( + const bool& value, + bool assert_fail) +{ + using T = bool; + CHECK_ARITHMETIC_UNARY_OPERATOR(value, assert_fail, ~, !value); +} + template inline void check_negate_operator( const T& value, @@ -108,6 +140,16 @@ inline void check_negate_operator( CHECK_ARITHMETIC_UNARY_OPERATOR(value, assert_fail, -); } +// in order to avoid warning C4804: -value == !value +template<> +inline void check_negate_operator( + const bool& value, + bool assert_fail) +{ + using T = bool; + CHECK_ARITHMETIC_UNARY_OPERATOR(value, assert_fail, -, !value); +} + TEST (DynamicDataOperators, arithmetic_unary_operators) { // Operator ~ available @@ -165,10 +207,26 @@ inline void check_arithmetic_flt_binary_operators( ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, /, _data, A / B); } +// in order to avoid warning C4804: handle arithmetica as boolean algebra +template<> +inline void check_arithmetic_flt_binary_operators( + const bool& A, + const bool& B) +{ + const DynamicType& type(primitive_type()); + DynamicData data(type), _data(type), res(type); + data = A; + _data = B; + + using T = bool; + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, +, _data, A || B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, *, _data, A && B); +} + #define ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(OPERAND1, OPERATOR, OPERAND2, RES) \ {\ std::stringstream errmsg;\ - errmsg << "Operator" << (#OPERATOR == "^" ? "\\^" : #OPERATOR) << "()";\ + errmsg << "Operator" << (#OPERATOR[0] == '^' ? "\\^" : #OPERATOR) << '()';\ ASSERT_OR_EXCEPTION(\ { ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(OPERAND1, OPERATOR, OPERAND2, RES);},\ errmsg.str());\ @@ -212,6 +270,42 @@ inline void check_arithmetic_int_binary_operators( } } +// in order to avoid warning C4804: handle arithmetica as boolean algebra +template <> +inline void check_arithmetic_int_binary_operators( + const bool& A, + const bool& B, + bool assert_fail) +{ + const DynamicType& type(primitive_type()); + DynamicData data(type), _data(type), res(type); + data = A; + _data = B; + + using T = bool; + if (assert_fail) + { + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(data, +, _data, A || B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(data, *, _data, A && B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(data, <<, _data, A); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(data, >>, _data, A && !B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(data, &, _data, A & B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(data, ^, _data, A ^ B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(data, |, _data, A | B); + } + else + { + + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, +, _data, A || B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, *, _data, A && B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, <<, _data, A); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, >>, _data, A && !B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, &, _data, A & B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, ^, _data, A ^ B); + ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, |, _data, A | B); + } +} + TEST (DynamicDataOperators, arithmetic_binary_operators) { // Operators available (all) @@ -435,6 +529,43 @@ inline void check_assignment_operators( } } +// in order to avoid warning C4804: handle arithmetica as boolean algebra +template <> +inline void check_assignment_operators( + const bool& A, + const bool& B, + bool assert_fail) +{ + const DynamicType& type(primitive_type()); + DynamicData data(type), _data(type), res(type); + data = A; + _data = B; + + using T = bool; + if (assert_fail) + { + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP_EXCEPT(data, +=, B, A || B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP_EXCEPT(data, *=, B, A && B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP_EXCEPT(data, &=, B, A & B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP_EXCEPT(data, ^=, B, A ^ B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP_EXCEPT(data, |=, B, A | B); + } + else + { + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, +=, _data, A || B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, *=, _data, A && B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, &=, _data, A & B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, ^=, _data, A ^ B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, |=, _data, A | B); + + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, +=, B, A || B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, *=, B, A && B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, &=, B, A & B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, ^=, B, A ^ B); + ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(data, |=, B, A | B); + } +} + TEST (DynamicDataOperators, assignment_operators) { // Operators available (all) diff --git a/test/unitary/xtypes/primitive_types.cpp b/test/unitary/xtypes/primitive_types.cpp index c7200fa3..991a4063 100644 --- a/test/unitary/xtypes/primitive_types.cpp +++ b/test/unitary/xtypes/primitive_types.cpp @@ -104,7 +104,7 @@ TEST (PrimitiveTypes, primitive_type_uint32) { EXPECT_TRUE(singleCheck(150000, 150000)); EXPECT_FALSE(singleCheck(150000, 150001)); - EXPECT_TRUE(singleCheck(-1, 0xFFFFFFFF)); + EXPECT_TRUE(singleCheck(std::numeric_limits::max(), 0xFFFFFFFF)); assignCheck(UINT32); } From 737860ac416ee74f042ebcf41883ef3009be0939 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 23 Dec 2022 15:06:03 +0100 Subject: [PATCH 07/49] Refs 16497. Fixing testing Signed-off-by: Miguel Barro --- include/xtypes/DynamicData.hpp | 1 - include/xtypes/PrimitiveType.hpp | 14 ++++++++++++++ test/unitary/xtypes/union_type.cpp | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/xtypes/DynamicData.hpp b/include/xtypes/DynamicData.hpp index 751101b4..907255b7 100644 --- a/include/xtypes/DynamicData.hpp +++ b/include/xtypes/DynamicData.hpp @@ -981,7 +981,6 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef "Expected type '" << type_.name() << "' but '" << PrimitiveTypeKindTrait::name << "' received while setting value."); - if (type_.is_enumerated_type()) { xtypes_assert(type_.memory_size() == sizeof(T), diff --git a/include/xtypes/PrimitiveType.hpp b/include/xtypes/PrimitiveType.hpp index 4ff28a6b..6d10942a 100644 --- a/include/xtypes/PrimitiveType.hpp +++ b/include/xtypes/PrimitiveType.hpp @@ -58,6 +58,20 @@ DDS_CORE_XTYPES_PRIMITIVE(char, CHAR_8_TYPE) DDS_CORE_XTYPES_PRIMITIVE(char16_t, CHAR_16_TYPE) DDS_CORE_XTYPES_PRIMITIVE(wchar_t, WIDE_CHAR_TYPE) +#define DDS_CORE_XTYPES_PRIMITIVE_ALIASES(ALIAS_TYPE, TYPE) \ + template<> \ + struct PrimitiveTypeKindTrait \ + { \ + static constexpr TypeKind kind = PrimitiveTypeKindTrait::kind\ + static constexpr const char* name = PrimitiveTypeKindTrait::name; \ + }; \ + +// Platform specific workarounds (stdint.h may miss some typedefs) +#ifdef _MSVC_VER +DDS_CORE_XTYPES_PRIMITIVE_ALIASES(long, int32_t) +DDS_CORE_XTYPES_PRIMITIVE_ALIASES(unsigned long, uint32_t) +#endif + /// \brief DynamicType representing a primitive type. /// Primitive types can be the following: bool char wchar_t uint8_t int16_t /// uint16_t int32_t uint32_t int64_t uint64_t float double long double. diff --git a/test/unitary/xtypes/union_type.cpp b/test/unitary/xtypes/union_type.cpp index d85cba57..38bf43df 100644 --- a/test/unitary/xtypes/union_type.cpp +++ b/test/unitary/xtypes/union_type.cpp @@ -194,8 +194,8 @@ TEST (UnionType, complex_union_and_default) EXPECT_NE(5000, data.get_member("array")[0].value()); // Modified when accessing as bool. // Change to st - data["st"]["uint64"] = 5000ul; - data["st"]["int64"] = -756757623l; + data["st"]["uint64"] = UINT64_C(5000); + data["st"]["int64"] = INT64_C(-756757623); data["st"]["float"] = 445.322f; EXPECT_EQ('b', data.d().value()); data.d('e'); From f1de241f3a3a3464810eb56b762eee188ce4c4d4 Mon Sep 17 00:00:00 2001 From: MiguelBarro Date: Thu, 29 Dec 2022 23:50:13 +0100 Subject: [PATCH 08/49] Refs 16497. Fixing testing Signed-off-by: MiguelBarro --- include/xtypes/DynamicDataImpl.hpp | 3 +-- include/xtypes/PrimitiveType.hpp | 4 ++-- test/unitary/xtypes/consistency.cpp | 5 ++++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/xtypes/DynamicDataImpl.hpp b/include/xtypes/DynamicDataImpl.hpp index 43967914..4eb463a5 100644 --- a/include/xtypes/DynamicDataImpl.hpp +++ b/include/xtypes/DynamicDataImpl.hpp @@ -72,8 +72,7 @@ namespace xtypes { MACRO(double, OPERATOR);\ case TypeKind::FLOAT_128_TYPE:\ MACRO(long double, OPERATOR);\ - default:\ - return *this;\ + default:;\ }\ } diff --git a/include/xtypes/PrimitiveType.hpp b/include/xtypes/PrimitiveType.hpp index 6d10942a..af4dfeff 100644 --- a/include/xtypes/PrimitiveType.hpp +++ b/include/xtypes/PrimitiveType.hpp @@ -62,12 +62,12 @@ DDS_CORE_XTYPES_PRIMITIVE(wchar_t, WIDE_CHAR_TYPE) template<> \ struct PrimitiveTypeKindTrait \ { \ - static constexpr TypeKind kind = PrimitiveTypeKindTrait::kind\ + static constexpr TypeKind kind = PrimitiveTypeKindTrait::kind; \ static constexpr const char* name = PrimitiveTypeKindTrait::name; \ }; \ // Platform specific workarounds (stdint.h may miss some typedefs) -#ifdef _MSVC_VER +#ifdef _MSC_VER DDS_CORE_XTYPES_PRIMITIVE_ALIASES(long, int32_t) DDS_CORE_XTYPES_PRIMITIVE_ALIASES(unsigned long, uint32_t) #endif diff --git a/test/unitary/xtypes/consistency.cpp b/test/unitary/xtypes/consistency.cpp index 81c48b5e..97bfa1f5 100644 --- a/test/unitary/xtypes/consistency.cpp +++ b/test/unitary/xtypes/consistency.cpp @@ -197,8 +197,11 @@ TEST (Consistency, testing_is_compatible_structure_of_primitive_type_float) EXPECT_EQ(TypeConsistency::EQUALS , the_str.is_compatible(other_str)); EXPECT_EQ(TypeConsistency::EQUALS , other_str.is_compatible(the_str)); EXPECT_EQ(TypeConsistency::IGNORE_TYPE_WIDTH, the_str.is_compatible(another_str)); - EXPECT_EQ(TypeConsistency::IGNORE_TYPE_WIDTH, the_str.is_compatible(another_more_str)); EXPECT_EQ(TypeConsistency::IGNORE_TYPE_WIDTH, another_str.is_compatible(another_more_str)); +#ifndef _MSC_VER + // on visual studio std::is_same::value == true + EXPECT_EQ(TypeConsistency::IGNORE_TYPE_WIDTH, the_str.is_compatible(another_more_str)); +#endif } TEST (Consistency, testing_is_compatible_structure_of_array_small_bound) From 48c42600586086b6874dd69b9fc86ff858057436 Mon Sep 17 00:00:00 2001 From: MiguelBarro Date: Fri, 30 Dec 2022 01:57:29 +0100 Subject: [PATCH 09/49] Refs 16497. Fixing testing Signed-off-by: MiguelBarro --- include/xtypes/DynamicDataImpl.hpp | 22 ++++++++++++++++++- test/unitary/xtypes/dynamicdata_operators.cpp | 15 ++++++------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/xtypes/DynamicDataImpl.hpp b/include/xtypes/DynamicDataImpl.hpp index 4eb463a5..4659a5cc 100644 --- a/include/xtypes/DynamicDataImpl.hpp +++ b/include/xtypes/DynamicDataImpl.hpp @@ -421,13 +421,33 @@ inline DynamicData DynamicData::operator OPERATOR (const ReadableDynamicDataRef& DYNAMIC_DATA_NUMERIC_OPERATOR_RESULT(OPERATOR);\ } +#define DYNAMIC_DATA_NUMERIC_SAFE_OPERATOR_IMPLEMENTATION(OPERATOR)\ +inline DynamicData DynamicData::operator OPERATOR (const ReadableDynamicDataRef& other) const \ +{\ + switch(type_.kind())\ + {\ + case TypeKind::CHAR_8_TYPE:\ + case TypeKind::CHAR_16_TYPE:\ + case TypeKind::WIDE_CHAR_TYPE:\ + case TypeKind::BOOLEAN_TYPE:\ + {\ + std::ostringstream os;\ + os << "Operator" << (#OPERATOR[0] == '^' ? "\\^" : #OPERATOR)\ + << " is not supported for type " << type_.name();\ + throw std::runtime_error(os.str());\ + }\ + default:\ + DYNAMIC_DATA_NUMERIC_OPERATOR_RESULT(OPERATOR);\ + }\ +} + DYNAMIC_DATA_NUMERIC_OPERATOR_IMPLEMENTATION(*); DYNAMIC_DATA_NUMERIC_OPERATOR_IMPLEMENTATION(/); DYNAMIC_DATA_NUMERIC_INT_OPERATOR_IMPLEMENTATION(%); -DYNAMIC_DATA_NUMERIC_OPERATOR_IMPLEMENTATION(+); +DYNAMIC_DATA_NUMERIC_SAFE_OPERATOR_IMPLEMENTATION(+); DYNAMIC_DATA_NUMERIC_OPERATOR_IMPLEMENTATION(-); diff --git a/test/unitary/xtypes/dynamicdata_operators.cpp b/test/unitary/xtypes/dynamicdata_operators.cpp index b0756785..50a94018 100644 --- a/test/unitary/xtypes/dynamicdata_operators.cpp +++ b/test/unitary/xtypes/dynamicdata_operators.cpp @@ -39,8 +39,8 @@ inline void check_de_increment_operators( if (assert_fail) { - ASSERT_OR_EXCEPTION({ ASSERT_EQ_DYNAMICDATA(data++, value + 1); }, "Operator++()"); - ASSERT_OR_EXCEPTION({ ASSERT_EQ_DYNAMICDATA(data--, value + 1); }, "Operator--()"); + ASSERT_OR_EXCEPTION({ ASSERT_EQ_DYNAMICDATA(data++, value + 1); }, R"xtypes(Operator\+\+\(\))xtypes"); + ASSERT_OR_EXCEPTION({ ASSERT_EQ_DYNAMICDATA(data--, value + 1); }, R"xtypes(Operator--\(\))xtypes"); } else { @@ -89,7 +89,7 @@ TEST (DynamicDataOperators, increment_decrement_operators) if (assert_fail)\ {\ ASSERT_OR_EXCEPTION({ ASSERT_EQ_DYNAMICDATA(OP(data), OP(value)); },\ - std::string("Operator") + #OP + "()");\ + std::string("Operator") + #OP + "\\(\\)");\ }\ else\ {\ @@ -106,7 +106,7 @@ TEST (DynamicDataOperators, increment_decrement_operators) if (assert_fail)\ {\ ASSERT_OR_EXCEPTION({ ASSERT_EQ_DYNAMICDATA(OP(data), (result)); },\ - std::string("Operator") + #OP + "()");\ + std::string("Operator") + #OP + "\\(\\)");\ }\ else\ {\ @@ -226,7 +226,7 @@ inline void check_arithmetic_flt_binary_operators( #define ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(OPERAND1, OPERATOR, OPERAND2, RES) \ {\ std::stringstream errmsg;\ - errmsg << "Operator" << (#OPERATOR[0] == '^' ? "\\^" : #OPERATOR) << '()';\ + errmsg << "Operator" << (#OPERATOR[0] == '^' ? "\\^" : #OPERATOR);\ ASSERT_OR_EXCEPTION(\ { ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(OPERAND1, OPERATOR, OPERAND2, RES);},\ errmsg.str());\ @@ -295,7 +295,6 @@ inline void check_arithmetic_int_binary_operators( } else { - ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, +, _data, A || B); ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, *, _data, A && B); ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(data, <<, _data, A); @@ -337,7 +336,7 @@ inline void check_logical_not_operator( data = value; if (assert_fail) { - ASSERT_OR_EXCEPTION({ ASSERT_EQ(!data, !value); }, "Operator!()"); + ASSERT_OR_EXCEPTION({ ASSERT_EQ(!data, !value); }, R"xtypes(Operator!\(\))xtypes"); } else { @@ -477,7 +476,7 @@ inline void check_assignment_flt_operators( {\ ASSERT_OR_EXCEPTION(\ { ASSERT_EQ_DYNAMICDATA_SELFASSIGN_OP(OPERAND1, OPERATOR, OPERAND2, RES);},\ - "Operator.*() cannot be used with non-arithmetic types");\ + R"xtypes(Operator.*\(\) cannot be used with non-arithmetic types)xtypes");\ } template From 0ced5c0191b51b1bf9e68d81ab6a2a0ec3c2dc61 Mon Sep 17 00:00:00 2001 From: MiguelBarro Date: Fri, 30 Dec 2022 17:22:34 +0100 Subject: [PATCH 10/49] Refs 16497. Populating test environment to locate preprocessor on windows Signed-off-by: MiguelBarro --- CMakeLists.txt | 29 +++++++++++++++++++++++++++++ test/environment.ps1 | 23 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 test/environment.ps1 diff --git a/CMakeLists.txt b/CMakeLists.txt index df91f658..ee263294 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,6 +167,11 @@ macro(compile_test) ) add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) + + if(TEST_EXTRA_VARIABLES) + set_property(TEST ${TEST_NAME} PROPERTY ENVIRONMENT "${TEST_EXTRA_VARIABLES}") + endif() + endmacro() if(XTYPES_BUILD_TESTS) @@ -176,6 +181,30 @@ if(XTYPES_BUILD_TESTS) # apt install libgtest-dev find_package(GTest CONFIG REQUIRED) + if(MSVC) + # Populate test environment if required + find_path(CL_BIN cl.exe) + + # if preprocessor is already available not populate + if(NOT CL_BIN) + execute_process( + COMMAND powershell -File "${CMAKE_CURRENT_LIST_DIR}\\test\\environment.ps1" + OUTPUT_VARIABLE EXTRA_ENVIRONMENT_OUTPUT) + endif() + + if(EXTRA_ENVIRONMENT_OUTPUT) + string(REGEX MATCH "^(.*)>><<(.*)$" EXTRA_ENVIRONMENT_OUTPUT "${EXTRA_ENVIRONMENT_OUTPUT}") + endif() + + set(TEST_EXTRA_VARIABLES "${CMAKE_MATCH_1}") + set(TEST_EXTRA_PATHS "Path=$ENV{Path};${CMAKE_MATCH_2}") + string(REPLACE ";" "\\;" TEST_EXTRA_PATHS "${TEST_EXTRA_PATHS}") + set(TEST_EXTRA_VARIABLES "${TEST_EXTRA_VARIABLES};${TEST_EXTRA_PATHS}") + unset(TEST_EXTRA_PATHS) + unset(EXTRA_ENVIRONMENT_OUTPUT) + + endif(MSVC) + compile_test(xtypes_test_unitary SOURCE test/unitary/xtypes/main.cpp test/unitary/xtypes/primitive_types.cpp diff --git a/test/environment.ps1 b/test/environment.ps1 new file mode 100644 index 00000000..e34bc40e --- /dev/null +++ b/test/environment.ps1 @@ -0,0 +1,23 @@ +# keep all variables +$old = ls env: +$oldpath = $old | ? name -eq Path +# load development environment +[xml]$info = & "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\installer\vswhere" ` + -latest -format xml +$pwshmodule = Join-Path $info.instances.instance.installationPath ` + "Common7\Tools\Microsoft.VisualStudio.DevShell.dll" | gi +Import-Module $pwshmodule +Enter-VsDevShell -VsInstanceId $info.instances.instance.instanceId | Out-Null +# keep new variables +$new = ls env: +$newpath = $new | ? name -eq Path +# output new variables +$cmp = Compare-Object -ReferenceObject $old -DifferenceObject $new +$output = ($cmp.InputObject | % { $_.key + "=" + ($_.value -replace ";","\;") }) -join ";" +$cmppath = Compare-Object -ReferenceObject $oldpath.value.split(";") ` + -DifferenceObject $newpath.value.split(";") +# Split using special char +$output += ">><<" +# output extra Paths +$output += $cmppath.InputObject -join ";" +Write-Output $output From 377a0dd9d628096ce55907b37e5e0e85c3960291 Mon Sep 17 00:00:00 2001 From: MiguelBarro Date: Sun, 1 Jan 2023 01:43:05 +0100 Subject: [PATCH 11/49] Refs 16497. Introducing some c++17 improvements Signed-off-by: MiguelBarro --- include/xtypes/idl/parser.hpp | 200 +++++++++++++++++++--------------- 1 file changed, 111 insertions(+), 89 deletions(-) diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 3f675635..7e2ce6d0 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -257,66 +258,34 @@ class PreprocessorContext return output; } - // preprocessing using pipes - std::string preprocess_string( - const std::string& idl_string, - std::true_type) const - { - std::string args; - for (const std::string& inc_path : include_paths) - { - args += include_flag + inc_path + " "; - } - // Escape double quotes inside the idl_string - std::string escaped_idl_string = idl_string; - replace_all_string(escaped_idl_string, "\"", "\\\""); - std::string cmd = "echo \"" + escaped_idl_string + "\" | " - + preprocessor_exec + " " + args + error_redir; + std::string preprocess_string(const std::string& idl_string) const; - log(log::LogLevel::DEBUG, "PREPROCESS", - "Calling preprocessor '" + preprocessor_exec + "' for an IDL string."); - - return exec(cmd); - } - - // preprocessing using files - std::string preprocess_string( - const std::string& idl_string, - std::false_type) const - { - static std::hash fn; - - // Create temporary filename - auto tmp = std::filesystem::temp_directory_path(); - tmp /= "xtypes_"; - tmp += fn(idl_string); - - { // Populate - std::ofstream os(tmp); - os << idl_string; - } - - auto processed = preprocess_file(tmp.string()); - - // dispose - std::filesystem::remove(tmp); +private: - return processed; - } + template + std::string preprocess_string(const std::string& idl_string) const; - std::string preprocess_string( - const std::string& idl_string) const + void replace_all_string( + std::string& str, + const std::string& from, + const std::string& to) const { - switch(strategy) + size_t froms = from.size(); + size_t tos = to.size(); + size_t pos = str.find(from); + const std::string escaped = "\\\\\""; + size_t escaped_size = escaped.size(); + while (pos != std::string::npos) { - case preprocess_strategy::pipe_stdin: - return preprocess_string(idl_string, std::true_type()); - case preprocess_strategy::temporary_file: - return preprocess_string(idl_string, std::false_type()); - } + str.replace(pos, froms, to); + pos = str.find(from, pos + tos); + while (str[pos - 1] == '\\') + { + str.replace(pos, froms, escaped); + pos = str.find(from, pos + escaped_size); + } - xtypes_assert(true, "unknown preprocessor strategy selected.") - return ""; + } } std::string exec( @@ -343,30 +312,68 @@ class PreprocessorContext return result; #endif // _MSC_VER } +}; - void replace_all_string( - std::string& str, - const std::string& from, - const std::string& to) const +// preprocessing using pipes +template<> +inline std::string PreprocessorContext::preprocess_string( + const std::string& idl_string) const +{ + std::string args; + for (const std::string& inc_path : include_paths) { - size_t froms = from.size(); - size_t tos = to.size(); - size_t pos = str.find(from); - const std::string escaped = "\\\\\""; - size_t escaped_size = escaped.size(); - while (pos != std::string::npos) - { - str.replace(pos, froms, to); - pos = str.find(from, pos + tos); - while (str[pos - 1] == '\\') - { - str.replace(pos, froms, escaped); - pos = str.find(from, pos + escaped_size); - } + args += include_flag + inc_path + " "; + } + // Escape double quotes inside the idl_string + std::string escaped_idl_string = idl_string; + replace_all_string(escaped_idl_string, "\"", "\\\""); + std::string cmd = "echo \"" + escaped_idl_string + "\" | " + + preprocessor_exec + " " + args + error_redir; - } + log(log::LogLevel::DEBUG, "PREPROCESS", + "Calling preprocessor '" + preprocessor_exec + "' for an IDL string."); + + return exec(cmd); +} + +// preprocessing using files +template<> +inline std::string PreprocessorContext::preprocess_string( + const std::string& idl_string) const +{ + static std::hash fn; + + // Create temporary filename + auto tmp = std::filesystem::temp_directory_path(); + tmp /= "xtypes_"; + tmp += fn(idl_string); + + { // Populate + std::ofstream os(tmp); + os << idl_string; } -}; + + auto processed = preprocess_file(tmp.string()); + + // dispose + std::filesystem::remove(tmp); + + return processed; +} + +inline std::string PreprocessorContext::preprocess_string( + const std::string& idl_string) const +{ + switch(strategy) + { + case preprocess_strategy::pipe_stdin: + return PreprocessorContext::preprocess_string(idl_string); + case preprocess_strategy::temporary_file: + return PreprocessorContext::preprocess_string(idl_string); + } + + xtypes_assert(true, "unknown preprocessor strategy selected.") +} class Parser; @@ -439,21 +446,39 @@ class Parser { public: - static Parser* instance() + static Parser* instance(bool create = true) { - Parser* instance = get_instance(); - if (instance == nullptr) + Parser* former_instance = instance_.load(); + + if (nullptr == former_instance && create) + { + Parser * new_instance = new Parser(); + + while(!instance_.compare_exchange_weak(former_instance, new_instance)) + { + if (former_instance != nullptr) + { + // other thread created a new instance + delete new_instance; + return former_instance; + } + } + + return new_instance; + } + else { - instance = new Parser(); + return former_instance; } - return instance; } static void destroy() { - Parser* instance = get_instance(); - delete instance; - instance = nullptr; + Parser* former_instance = instance_.exchange(nullptr); + if ( former_instance != nullptr ) + { + delete former_instance; + } } Parser() @@ -613,12 +638,7 @@ class Parser peg::parser parser_; Context* context_; std::shared_ptr root_scope_; - - static Parser* get_instance() - { - static Parser* instance_ = nullptr; - return instance_; - } + static std::atomic instance_; void parser_log_cb_( size_t l, @@ -2108,11 +2128,13 @@ class Parser }; +inline std::atomic Parser::instance_{nullptr}; + void Context::clear_context() { if (clear) { - if (Parser::get_instance() == instance_) + if (Parser::instance(false) == instance_) { Parser::destroy(); } From abdc04bdb248a0342661f11640e4378ea36696da Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 10 Jan 2023 12:22:31 +0100 Subject: [PATCH 12/49] Refs 16497. Fixing encoding issues. Signed-off-by: Miguel Barro --- CMakeLists.txt | 15 ++++++++++----- test/unitary/parser/parser_test.cpp | 11 +++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee263294..b77f9c7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,9 @@ if(MSVC) execute_process(COMMAND powershell -Command "$binarydir = \"${PROJECT_BINARY_DIR}\";" [=[ $header = gi "$binarydir/thirdparty/cpp-peglib/peglib.h"; - (cat $header | % { $_ -replace '__cplusplus', '_MSVC_LANG' } ) | Set-Content $header + (Get-Content -Encoding UTF8 -Path $header | + % { $_ -replace '__cplusplus', '_MSVC_LANG' } ) | + Set-Content -Encoding UTF8 -Path $header ]=] WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) @@ -54,10 +56,13 @@ target_include_directories(xtypes target_compile_features(xtypes INTERFACE cxx_std_17 cxx_variadic_macros) if(MSVC) - # target_compile_features() only enforces standard values like cxx_std_17. All other values like - # cxx_variadic_macros are not enforced using flags but only will generate an error if not available. - # CMake docs is misguiding (see cmGeneratorTarget::ComputeCompileFeatures implementation). - target_compile_options(xtypes INTERFACE /Zc:preprocessor) + # Preprocessor: + # target_compile_features() only enforces standard values like cxx_std_17. All other values like + # cxx_variadic_macros are not enforced using flags but only will generate an error if not available. + # CMake docs is misguiding (see cmGeneratorTarget::ComputeCompileFeatures implementation). + # Encoding: + # The header uses non-basic character set characters in narrow strings. Execution charset is hinted to allow UTF-8 + target_compile_options(xtypes INTERFACE /Zc:preprocessor /execution-charset:UTF-8) endif(MSVC) ##################################################################################### diff --git a/test/unitary/parser/parser_test.cpp b/test/unitary/parser/parser_test.cpp index 40bd4a37..9861e6f9 100644 --- a/test/unitary/parser/parser_test.cpp +++ b/test/unitary/parser/parser_test.cpp @@ -22,6 +22,17 @@ using namespace eprosima::xtypes; using namespace eprosima::xtypes::idl; +TEST (IDLParser, check_grammar) +{ + peg::parser parser; + + parser.set_logger([](size_t line, size_t col, const std::string& msg, const std::string &) { + std::cerr << line << ":" << col << ": " << msg << std::endl; + }); + + ASSERT_TRUE(parser.load_grammar(eprosima::xtypes::idl::idl_grammar())) << "grammar cannot be parsed"; +} + TEST (IDLParser, simple_struct_test) { Context context = parse( From caedbef40a1a223d6f246eb62c328253a899e4d4 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 10 Jan 2023 14:25:54 +0100 Subject: [PATCH 13/49] Refs 16497. Enabling ctest for individual gtest execution Signed-off-by: Miguel Barro --- CMakeLists.txt | 41 ++++++++------------ include/xtypes/idl/parser.hpp | 2 +- test/environment.ps1 | 59 +++++++++++++++++++++++------ test/unitary/parser/parser_test.cpp | 1 + 4 files changed, 65 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b77f9c7e..643a7902 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,15 @@ ##################################################################################### # Top xtypes build system ##################################################################################### -cmake_minimum_required(VERSION 3.16.3 FATAL_ERROR) + +if(MSVC) + cmake_minimum_required(VERSION 3.22) +else() + cmake_minimum_required(VERSION 3.16.3..3.22) +endif() project(xtypes - VERSION "0.1.0" + VERSION "0.2.0" LANGUAGES CXX ) @@ -108,7 +113,6 @@ if(XTYPES_BUILD_TOOLS OR NODERED_EXECUTABLE) if (NODERED_EXECUTABLE) file(WRITE ${TMP_ROOT}/idl_parser_path.txt "${PROJECT_BINARY_DIR}") - message("${PROJECT_BINARY_DIR}") endif() unset(TMP_ROOT) @@ -161,7 +165,7 @@ macro(compile_test) else() set(TEST_NAME "${ARGV0}") endif() - set(multiValueArgs SOURCE) + set(multiValueArgs SOURCE PROPERTIES) cmake_parse_arguments(TEST "" "${uniValueArgs}" "${multiValueArgs}" ${ARGN}) compile_example(${TEST_NAME} SOURCE ${TEST_SOURCE}) @@ -171,11 +175,7 @@ macro(compile_test) GTest::gtest ) - add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) - - if(TEST_EXTRA_VARIABLES) - set_property(TEST ${TEST_NAME} PROPERTY ENVIRONMENT "${TEST_EXTRA_VARIABLES}") - endif() + gtest_discover_tests(${TEST_NAME} PROPERTIES ${TEST_PROPERTIES} ${MSVC_TEST_PROPERTIES}) endmacro() @@ -185,8 +185,10 @@ if(XTYPES_BUILD_TESTS) # apt install libgtest-dev find_package(GTest CONFIG REQUIRED) + include(GoogleTest) if(MSVC) + # Populate test environment if required find_path(CL_BIN cl.exe) @@ -194,19 +196,11 @@ if(XTYPES_BUILD_TESTS) if(NOT CL_BIN) execute_process( COMMAND powershell -File "${CMAKE_CURRENT_LIST_DIR}\\test\\environment.ps1" - OUTPUT_VARIABLE EXTRA_ENVIRONMENT_OUTPUT) - endif() - - if(EXTRA_ENVIRONMENT_OUTPUT) - string(REGEX MATCH "^(.*)>><<(.*)$" EXTRA_ENVIRONMENT_OUTPUT "${EXTRA_ENVIRONMENT_OUTPUT}") + OUTPUT_VARIABLE MSVC_TEST_PROPERTIES) endif() - set(TEST_EXTRA_VARIABLES "${CMAKE_MATCH_1}") - set(TEST_EXTRA_PATHS "Path=$ENV{Path};${CMAKE_MATCH_2}") - string(REPLACE ";" "\\;" TEST_EXTRA_PATHS "${TEST_EXTRA_PATHS}") - set(TEST_EXTRA_VARIABLES "${TEST_EXTRA_VARIABLES};${TEST_EXTRA_PATHS}") - unset(TEST_EXTRA_PATHS) - unset(EXTRA_ENVIRONMENT_OUTPUT) + # Remove any console line feeds + string(STRIP "${MSVC_TEST_PROPERTIES}" MSVC_TEST_PROPERTIES) endif(MSVC) @@ -225,17 +219,14 @@ if(XTYPES_BUILD_TESTS) compile_test(xtypes_test_unitary_no_memcheck SOURCE test/unitary/xtypes/main.cpp - test/unitary/xtypes/no_memcheck_tests.cpp) + test/unitary/xtypes/no_memcheck_tests.cpp + PROPERTIES LABELS "NoMemoryCheck") compile_test(xtypes_idl_parser_test_unitary SOURCE test/unitary/parser/module.cpp test/unitary/parser/parser_test.cpp) compile_test(xtypes_idl_parser_roundtrip SOURCE test/unitary/parser/roundtrip.cpp) compile_test(xtypes_idl_generator_dependencies SOURCE test/unitary/generator/dependencies.cpp) - # ... - - # Set test with label NoMemoryCheck - set_property(TEST xtypes_test_unitary_no_memcheck PROPERTY LABELS "NoMemoryCheck") # Copy IDL files configure_file( diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 7e2ce6d0..fa14d7d5 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -510,6 +510,7 @@ class Parser { context.instance_ = this; context_ = &context; + context.module_ = &root_scope_; std::shared_ptr ast; if (!parser_.parse(idl_string.c_str(), ast)) @@ -522,7 +523,6 @@ class Parser ast = parser_.optimize_ast(ast); build_on_ast(ast); - context.module_ = root_scope_; context.success = true; context_->log(log::LogLevel::DEBUG, "RESULT", "The parser finished."); diff --git a/test/environment.ps1 b/test/environment.ps1 index e34bc40e..a9898bd4 100644 --- a/test/environment.ps1 +++ b/test/environment.ps1 @@ -1,6 +1,5 @@ # keep all variables $old = ls env: -$oldpath = $old | ? name -eq Path # load development environment [xml]$info = & "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\installer\vswhere" ` -latest -format xml @@ -10,14 +9,50 @@ Import-Module $pwshmodule Enter-VsDevShell -VsInstanceId $info.instances.instance.instanceId | Out-Null # keep new variables $new = ls env: -$newpath = $new | ? name -eq Path -# output new variables -$cmp = Compare-Object -ReferenceObject $old -DifferenceObject $new -$output = ($cmp.InputObject | % { $_.key + "=" + ($_.value -replace ";","\;") }) -join ";" -$cmppath = Compare-Object -ReferenceObject $oldpath.value.split(";") ` - -DifferenceObject $newpath.value.split(";") -# Split using special char -$output += ">><<" -# output extra Paths -$output += $cmppath.InputObject -join ";" -Write-Output $output +# compare old and new environment +$raw = Compare-Object -ReferenceObject $old -DifferenceObject $new -Property key, value + +# Split collections +$PathVars, $Vars = $raw | Group-Object {$_.key -match "Path|INCLUDE|LIB"} | Sort-Object Name -Descending + +$PathVars = $PathVars.Group | Group-Object key + +# New variables +$Vars = $Vars.Group +$output = $Vars | % { '{0}={1}' -f $_.key, $_.value } | + Add-Member -NotePropertyMembers @{PropertyName="ENVIRONMENT"} -PassThru + +# New Paths +$NewPaths = ($PathVars | ? Count -eq 1).Group +$NewPaths | % { + $name = $_.key + $values = $_.value -split ";" + $output += '{0}={1}' -f $name, $values[0] | + Add-Member -NotePropertyMembers @{PropertyName="ENVIRONMENT"} -PassThru + $output += $values | select -skip 1 | + % {'{0}=path_list_append:{1}' -f $name, $_} | + Add-Member -NotePropertyMembers @{PropertyName="ENVIRONMENT_MODIFICATION"} -PassThru +} + +# Paths to update +$UpdatePaths = ($PathVars | ? Count -eq 2).Name + +$UpdatePaths | % { + $name = $_ + $filt = {$_.key -eq $name} + $cmp = Compare-Object -ReferenceObject $old.Where($filt).value.split(";") ` + -DifferenceObject $new.Where($filt).value.split(";") + $output += $cmp.InputObject | % {'{0}=path_list_append:{1}' -f $name, $_} | + Add-Member -NotePropertyMembers @{PropertyName="ENVIRONMENT_MODIFICATION"} -PassThru +} + +## Saving space using lists is not an option because add_custom_command() forces ; expansion +#$p_env, $p_envmod = $output | Group-Object -Property PropertyName | +# Sort-Object -Property Name +# $output = @() + $p_env.Name + $p_env.Group + $p_envmod.Name + $p_envmod.Group -join ";" + +$output = ($output | Group-Object -Property PropertyName | + % { $name = $_.Name; $_.Group | % { $name; $_ } }) -join ";" + +# Return a single string properly formatted for cmake taste +$output.replace("\","/") diff --git a/test/unitary/parser/parser_test.cpp b/test/unitary/parser/parser_test.cpp index 9861e6f9..82cbbe7d 100644 --- a/test/unitary/parser/parser_test.cpp +++ b/test/unitary/parser/parser_test.cpp @@ -739,6 +739,7 @@ TEST (IDLParser, const_value_parser) TEST (IDLParser, parse_file) { Context context = parse_file("idl/test01.idl"); + ASSERT_TRUE(context.success); std::map result = context.module().get_all_types(); EXPECT_EQ(1, result.size()); const DynamicType* my_struct = result["Test01"].get(); From 1e95e8a3c4b337dcf74203eda811974a48c7dcc3 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 10 Jan 2023 14:57:47 +0100 Subject: [PATCH 14/49] Refs 16497. Fixing Parser::is_token() Signed-off-by: Miguel Barro --- include/xtypes/idl/parser.hpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index fa14d7d5..c02b3dd5 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -726,7 +726,7 @@ class Parser return std::string(identifier.substr(1).data(), identifier.substr(1).size()); // If the identifier starts with "_", remove the underscode and return. } - if (ast->is_token) + if (is_token(identifier)) { std::stringstream message; message << "The identifier \"" << identifier << "\" is a reserved word."; @@ -765,6 +765,29 @@ class Parser }); } + bool is_token( + const std::string_view& identifier) + { + std::string aux_id(identifier.data(), identifier.size()); + + if (context_->ignore_case) + { + to_lower(aux_id); + } + + for (const auto& rule : parser_.get_grammar()) + { + if (rule.first.find("KW_") == 0) // If it starts with "KW_", is a reserved word. You are welcome. + { + if (rule.second.parse(aux_id.c_str()).ret) + { + return true; + } + } + } + return false; + } + void module_dcl( const std::shared_ptr& ast, std::shared_ptr& outer) From 2d8208663714fde4e392c4fd24e70f35ae16786b Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Wed, 11 Jan 2023 10:42:10 +0100 Subject: [PATCH 15/49] Refs 16497. Refactor static Parser object lifeliness Signed-off-by: Miguel Barro --- include/xtypes/idl/idl.hpp | 8 ++-- include/xtypes/idl/parser.hpp | 69 ++++++++++++----------------------- 2 files changed, 27 insertions(+), 50 deletions(-) diff --git a/include/xtypes/idl/idl.hpp b/include/xtypes/idl/idl.hpp index fe5b58b5..8d9b811a 100644 --- a/include/xtypes/idl/idl.hpp +++ b/include/xtypes/idl/idl.hpp @@ -34,7 +34,7 @@ namespace idl { inline Context parse( const std::string& idl) { - Parser* parser = Parser::instance(); + std::shared_ptr parser = Parser::instance(); return parser->parse(idl); } @@ -44,7 +44,7 @@ inline Context& parse( const std::string& idl, Context& context) { - Parser* parser = Parser::instance(); + std::shared_ptr parser = Parser::instance(); parser->parse(idl.c_str(), context); return context; } @@ -54,7 +54,7 @@ inline Context& parse( inline Context parse_file( const std::string& idl_file) { - Parser* parser = Parser::instance(); + std::shared_ptr parser = Parser::instance(); return parser->parse_file(idl_file); } @@ -64,7 +64,7 @@ inline Context& parse_file( const std::string& idl_file, Context& context) { - Parser* parser = Parser::instance(); + std::shared_ptr parser = Parser::instance(); parser->parse_file(idl_file.c_str(), context); return context; } diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index c02b3dd5..62f7c8f5 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -32,7 +32,6 @@ #include #include -#include #include #include #include @@ -42,6 +41,7 @@ #include #include #include +#include #include #include @@ -434,8 +434,8 @@ class Context private: friend class Parser; - Parser* instance_; - std::shared_ptr module_ = nullptr; + std::shared_ptr instance_; + Module* module_ = nullptr; inline void clear_context(); }; @@ -443,42 +443,25 @@ class Context static const Context DEFAULT_CONTEXT = Context(); class Parser + : public std::enable_shared_from_this { public: - static Parser* instance(bool create = true) + static std::shared_ptr instance(bool create = true) { - Parser* former_instance = instance_.load(); - - if (nullptr == former_instance && create) + if (!instance_ && create) { - Parser * new_instance = new Parser(); - - while(!instance_.compare_exchange_weak(former_instance, new_instance)) - { - if (former_instance != nullptr) - { - // other thread created a new instance - delete new_instance; - return former_instance; - } - } - - return new_instance; - } - else - { - return former_instance; + std::lock_guard _(mtx_); + instance_ = std::make_shared(); } + + return instance_; } static void destroy() { - Parser* former_instance = instance_.exchange(nullptr); - if ( former_instance != nullptr ) - { - delete former_instance; - } + std::lock_guard _(mtx_); + instance_.reset(); } Parser() @@ -508,7 +491,7 @@ class Parser const std::string& idl_string, Context& context) { - context.instance_ = this; + context.instance_ = shared_from_this(); context_ = &context; context.module_ = &root_scope_; std::shared_ptr ast; @@ -549,7 +532,7 @@ class Parser const std::string& idl_file, Context& context) { - context.instance_ = this; + context.instance_ = shared_from_this(); context_ = &context; std::shared_ptr ast; if (context.preprocess) @@ -567,7 +550,7 @@ class Parser const std::string& idl_string, Context& context) { - context.instance_ = this; + context.instance_ = shared_from_this(); if (context.preprocess) { @@ -582,10 +565,7 @@ class Parser void get_all_types( std::map& types_map) { - if (root_scope_) - { - root_scope_->fill_all_types(types_map); - } + root_scope_.fill_all_types(types_map); } class exception : public std::runtime_error @@ -637,8 +617,9 @@ class Parser peg::parser parser_; Context* context_; - std::shared_ptr root_scope_; - static std::atomic instance_; + Module root_scope_; + static std::shared_ptr instance_; + static std::mutex mtx_; void parser_log_cb_( size_t l, @@ -657,11 +638,7 @@ class Parser using namespace peg::udl; if (scope == nullptr) { - if (context_->clear || root_scope_ == nullptr) - { - root_scope_ = std::make_shared(); - } - scope = root_scope_; + scope = std::shared_ptr(&root_scope_,[](Module*){}); } switch (ast->tag){ case "ANNOTATION_APPL"_: @@ -2151,7 +2128,8 @@ class Parser }; -inline std::atomic Parser::instance_{nullptr}; +inline std::shared_ptr Parser::instance_; +inline std::mutex Parser::mtx_; void Context::clear_context() { @@ -2163,8 +2141,7 @@ void Context::clear_context() } else { - delete instance_; - instance_ = nullptr; + instance_.reset(); } } } From 7a78e99de4cfbb7b0bfd2abff334ae98469bdf34 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Thu, 12 Jan 2023 15:36:58 +0100 Subject: [PATCH 16/49] Refs 16497. Fix pipes crossplatform issues Signed-off-by: Miguel Barro --- include/xtypes/idl/parser.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 62f7c8f5..83896c34 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -60,12 +60,14 @@ # define EPROSIMA_PLATFORM_PREPROCESSOR "cl /EP" # define EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY preprocess_strategy::temporary_file # define EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES "/I" -# define EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR " 2> nul" +# define EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR " 2>nul" +# define EPROSIMA_PLATFORM_PIPE_OPEN_FLAGS "rt" #else # define EPROSIMA_PLATFORM_PREPROCESSOR "cpp -H" # define EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY preprocess_strategy::pipe_stdin # define EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES "-I " -# define EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR " 2> /dev/null" +# define EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR " 2>/dev/null" +# define EPROSIMA_PLATFORM_PIPE_OPEN_FLAGS "r" #endif namespace peg { @@ -291,7 +293,9 @@ class PreprocessorContext std::string exec( const std::string& cmd) const { - std::unique_ptr pipe(popen(cmd.c_str(), "rt"), pclose); + std::cerr << cmd.c_str() << std::endl; + std::unique_ptr pipe( + popen(cmd.c_str(), EPROSIMA_PLATFORM_PIPE_OPEN_FLAGS), pclose); if (!pipe) { throw std::runtime_error("popen() failed!"); From 9bb112e9cd26dbc2a489e38bfa5a63fa4b03b011 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 13 Jan 2023 11:07:11 +0100 Subject: [PATCH 17/49] Refs 16497. Refactor temporary filename generation. Fixings on crossplatform command line piping. Signed-off-by: Miguel Barro --- CMakeLists.txt | 2 + include/xtypes/Assert.hpp | 25 +++- include/xtypes/idl/generator.hpp | 6 +- include/xtypes/idl/generator_deptree.hpp | 48 +++--- include/xtypes/idl/idl.hpp | 4 +- include/xtypes/idl/parser.hpp | 180 ++++++++++++++--------- test/unitary/parser/parser_test.cpp | 22 +-- test/unitary/xtypes/primitive_types.cpp | 48 +++--- test/unitary/xtypes/struct_type.cpp | 162 ++++++++++---------- tools/idl_validator.cpp | 2 +- 10 files changed, 278 insertions(+), 221 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 643a7902..5c696fb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,8 @@ add_library(eprosima::xtypes ALIAS xtypes) if(XTYPES_EXCEPTIONS) target_compile_definitions(xtypes INTERFACE XTYPES_EXCEPTIONS) +elseif(MSVC) + target_link_libraries(xtypes INTERFACE Dbghelp.lib) endif() # Download the cpp-peglib header file needed diff --git a/include/xtypes/Assert.hpp b/include/xtypes/Assert.hpp index cd6fdb8e..da7c1b8b 100644 --- a/include/xtypes/Assert.hpp +++ b/include/xtypes/Assert.hpp @@ -34,14 +34,16 @@ # include #endif -#include +#include + +#include #include namespace { // auxiliary structure struct symbol_desc : SYMBOL_INFO { - CHAR [1023]; // name buffer + CHAR _[1023]; // name buffer symbol_desc() { @@ -76,7 +78,7 @@ namespace { \ for( int i = 0; i < frames; ++i) \ { \ - SymFromAddr( hProcess, static_cast(callstack[i]), 0, &symbol); \ + SymFromAddr( hProcess, reinterpret_cast(callstack[i]), 0, &symbol); \ tstring name = symbol.Name; \ if (name.empty()) \ { \ @@ -165,5 +167,22 @@ namespace { #define GET_MACRO(_1, _2, _3, NAME, ...) NAME #define xtypes_assert(...) GET_MACRO(__VA_ARGS__, xtypes_assert3_, xtypes_assert2_)(__VA_ARGS__) +namespace { +#if __has_include() +# include +# ifdef __cpp_lib_unreachable +using std::unreachable; +# else +[[noreturn]] inline void unreachable() +{ +# ifdef __GNUC__ // GCC, Clang, ICC + __builtin_unreachable(); +# elif defined(_MSC_VER) // MSVC + __assume(false); +# endif +} +# endif +#endif // version +} // namespace #endif // EPROSIMA_XTYPES_ASSERT_HPP_ diff --git a/include/xtypes/idl/generator.hpp b/include/xtypes/idl/generator.hpp index cb4f1d24..0e511e4c 100644 --- a/include/xtypes/idl/generator.hpp +++ b/include/xtypes/idl/generator.hpp @@ -291,7 +291,7 @@ inline std::string structure( { if (struct_node != nullptr) { - dependencynode_assert(struct_node, STRUCT); + dependencynode_assert(struct_node, xSTRUCT); } std::stringstream ss; @@ -326,7 +326,7 @@ inline std::string generate_union( dependencytree::DependencyNode* union_node, size_t tabs) { - dependencynode_assert(union_node, UNION); + dependencynode_assert(union_node, xUNION); std::stringstream ss; ss << std::string(tabs * 4, ' ') << "union " << name @@ -369,7 +369,7 @@ inline std::string aliase( const DynamicType& type, dependencytree::DependencyNode* alias_node) { - dependencynode_assert(alias_node, ALIAS); + dependencynode_assert(alias_node, xALIAS); std::stringstream ss; ss << "typedef " << generator::type_name(alias_node, type) << " " << name; diff --git a/include/xtypes/idl/generator_deptree.hpp b/include/xtypes/idl/generator_deptree.hpp index 3f0f4e36..931d0b93 100644 --- a/include/xtypes/idl/generator_deptree.hpp +++ b/include/xtypes/idl/generator_deptree.hpp @@ -77,13 +77,13 @@ using ModuleRefSet = std::vector>; /// This enumeration reflects all possible kinds for a Module's content element. enum class ModuleElementKind { - ALIAS, - CONST, - ENUM, - STRUCT, - UNION/*, - STRUCT_FW, - UNION_FW*/ + xALIAS, + xCONST, + xENUM, + xSTRUCT, + xUNION/*, + xSTRUCT_FW, + xUNION_FW*/ }; /// \brief A class to set a hierarchy between Module's contents. @@ -293,12 +293,12 @@ class DependencyNode switch(kind_) { - case ModuleElementKind::ALIAS: + case ModuleElementKind::xALIAS: { ss << std::string(4 * tabs, ' ') << aliase(name(), static_cast(type()).get(), this); break; } - case ModuleElementKind::CONST: + case ModuleElementKind::xCONST: { for (const auto& pair : module_.constants_) { @@ -312,17 +312,17 @@ class DependencyNode } break; } - case ModuleElementKind::ENUM: + case ModuleElementKind::xENUM: { ss << enumeration32(name(), static_cast&>(type()), tabs); break; } - case ModuleElementKind::STRUCT: + case ModuleElementKind::xSTRUCT: { ss << structure(name(), static_cast(type()), this, tabs); break; } - case ModuleElementKind::UNION: + case ModuleElementKind::xUNION: { ss << generate_union(name(), static_cast(type()), this, tabs); break; @@ -646,11 +646,11 @@ class DependencyModule /// \brief Create a DependencyNode set for this DependencyModule. inline void create_dependency_set() { - ADD_INTO_DEPENDENCY_SET(module_.aliases_, ALIAS); - ADD_INTO_DEPENDENCY_SET(module_.constants_types_, CONST); - ADD_INTO_DEPENDENCY_SET(module_.enumerations_32_, ENUM); - ADD_INTO_DEPENDENCY_SET(module_.structs_, STRUCT); - ADD_INTO_DEPENDENCY_SET(module_.unions_, UNION); + ADD_INTO_DEPENDENCY_SET(module_.aliases_, xALIAS); + ADD_INTO_DEPENDENCY_SET(module_.constants_types_, xCONST); + ADD_INTO_DEPENDENCY_SET(module_.enumerations_32_, xENUM); + ADD_INTO_DEPENDENCY_SET(module_.structs_, xSTRUCT); + ADD_INTO_DEPENDENCY_SET(module_.unions_, xUNION); } /// \brief Looks for an specific module in the shared_ptr tree, given its pointer. @@ -884,28 +884,28 @@ class DependencyModule { switch (node.kind()) { - case ModuleElementKind::ALIAS: + case ModuleElementKind::xALIAS: { const AliasType& alias = static_cast(node.type()); set_dynamic_type_dependency(node, *alias, alias->name()); break; } - case ModuleElementKind::CONST: + case ModuleElementKind::xCONST: { const DynamicType& const_type = node.type(); set_dynamic_type_dependency(node, const_type, const_type.name()); break; } - case ModuleElementKind::ENUM: + case ModuleElementKind::xENUM: { const EnumerationType& enum_type = static_cast&>(node.type()); set_dynamic_type_dependency(node, enum_type, enum_type.name()); break; } - case ModuleElementKind::STRUCT: + case ModuleElementKind::xSTRUCT: { // TODO: detect if we are setting cyclical struct dependencies, and generate a forward declaration. const StructType& structure = static_cast(node.type()); @@ -925,7 +925,7 @@ class DependencyModule }); break; } - case ModuleElementKind::UNION: + case ModuleElementKind::xUNION: { // TODO: detect if we are setting cyclical union dependencies, and generate a forward declaration. const UnionType& union_type = static_cast(node.type()); @@ -940,8 +940,8 @@ class DependencyModule break; } /* - case ModuleElementKind::STRUCT_FW: - case ModuleElementKind::UNION_FW: + case ModuleElementKind::xSTRUCT_FW: + case ModuleElementKind::xUNION_FW: */ default: { diff --git a/include/xtypes/idl/idl.hpp b/include/xtypes/idl/idl.hpp index 8d9b811a..b4bb2470 100644 --- a/include/xtypes/idl/idl.hpp +++ b/include/xtypes/idl/idl.hpp @@ -35,7 +35,7 @@ inline Context parse( const std::string& idl) { std::shared_ptr parser = Parser::instance(); - return parser->parse(idl); + return parser->parse_string(idl); } /// \brief Same as parse() but it receives an existant context. @@ -45,7 +45,7 @@ inline Context& parse( Context& context) { std::shared_ptr parser = Parser::instance(); - parser->parse(idl.c_str(), context); + parser->parse_string(idl.c_str(), context); return context; } diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 83896c34..a07bd128 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -84,10 +85,10 @@ namespace log { enum LogLevel { - ERROR, - WARNING, - INFO, - DEBUG + xERROR, + xWARNING, + xINFO, + xDEBUG }; struct LogEntry @@ -121,16 +122,16 @@ struct LogEntry ss << "["; switch (level) { - case ERROR: + case xERROR: ss << "ERROR"; break; - case WARNING: + case xWARNING: ss << "WARNING"; break; - case INFO: + case xINFO: ss << "INFO"; break; - case DEBUG: + case xDEBUG: ss << "DEBUG"; break; } @@ -155,7 +156,7 @@ struct LogEntry class LogContext { mutable std::vector log_; - log::LogLevel log_level_ = log::LogLevel::WARNING; + log::LogLevel log_level_ = log::LogLevel::xWARNING; bool print_log_ = false; public: @@ -228,6 +229,29 @@ class PreprocessorContext { public: + PreprocessorContext() = default; + + PreprocessorContext(const PreprocessorContext& pc) + : preprocess(pc.preprocess) + , preprocessor_exec(pc.preprocessor_exec) + , error_redir(pc.error_redir) + , strategy(pc.strategy) + , include_flag(pc.include_flag) + , include_paths(pc.include_paths) + {} + + PreprocessorContext& operator=(const PreprocessorContext& pc) + { + preprocess = pc.preprocess; + preprocessor_exec = pc.preprocessor_exec; + error_redir = pc.error_redir; + strategy = pc.strategy; + include_flag = pc.include_flag; + include_paths = pc.include_paths; + + return *this; + } + // Preprocessors capability to use shared memory (pipes) or stick to file input enum class preprocess_strategy { @@ -241,6 +265,7 @@ class PreprocessorContext preprocess_strategy strategy = EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY; std::string include_flag = EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES; std::vector include_paths; + mutable std::random_device rd; std::string preprocess_file( const std::string& idl_file) const @@ -254,7 +279,7 @@ class PreprocessorContext std::string cmd = preprocessor_exec + " " + args + idl_file + error_redir; - log(log::LogLevel::DEBUG, "PREPROCESS", + log(log::LogLevel::xDEBUG, "PREPROCESS", "Calling preprocessor with command: " + cmd); std::string output = exec(cmd); return output; @@ -293,7 +318,6 @@ class PreprocessorContext std::string exec( const std::string& cmd) const { - std::cerr << cmd.c_str() << std::endl; std::unique_ptr pipe( popen(cmd.c_str(), EPROSIMA_PLATFORM_PIPE_OPEN_FLAGS), pclose); if (!pipe) @@ -334,7 +358,7 @@ inline std::string PreprocessorContext::preprocess_string inline std::string PreprocessorContext::preprocess_string( const std::string& idl_string) const { - static std::hash fn; - // Create temporary filename auto tmp = std::filesystem::temp_directory_path(); tmp /= "xtypes_"; - tmp += fn(idl_string); + + { // random name generator + std::ostringstream os; + std::uniform_int_distribution<> dist(65,90); + std::mt19937 gen(rd()); + + for (int n = 0; n < 16; ++n) + { + os << char(dist(gen)); + } + + tmp += os.str(); + } { // Populate std::ofstream os(tmp); @@ -376,7 +410,9 @@ inline std::string PreprocessorContext::preprocess_string( return PreprocessorContext::preprocess_string(idl_string); } - xtypes_assert(true, "unknown preprocessor strategy selected.") + xtypes_assert(true, "unknown preprocessor strategy selected.", true) + + unreachable(); } class Parser; @@ -503,7 +539,7 @@ class Parser if (!parser_.parse(idl_string.c_str(), ast)) { context.success = false; - context_->log(log::LogLevel::DEBUG, "RESULT", + context_->log(log::LogLevel::xDEBUG, "RESULT", "The parser found errors while parsing."); return false; } @@ -511,7 +547,7 @@ class Parser ast = parser_.optimize_ast(ast); build_on_ast(ast); context.success = true; - context_->log(log::LogLevel::DEBUG, "RESULT", + context_->log(log::LogLevel::xDEBUG, "RESULT", "The parser finished."); return true; } @@ -631,7 +667,7 @@ class Parser const std::string& msg ) const { - context_->log(log::DEBUG, "PEGLIB_PARSER", msg + " (" + std::to_string( + context_->log(log::xDEBUG, "PEGLIB_PARSER", msg + " (" + std::to_string( l - CPP_PEGLIB_LINE_COUNT_ERROR) + ":" + std::to_string(c) + ")"); } @@ -703,7 +739,7 @@ class Parser std::stringstream message; message << "The identifier \"" << identifier << "\" is escaped. It will be replaced by \"" << identifier.substr(1) << "\""; - context_->log(log::LogLevel::INFO, "ESCAPED_IDENTIFIER", message.str(), ast); + context_->log(log::LogLevel::xINFO, "ESCAPED_IDENTIFIER", message.str(), ast); return std::string(identifier.substr(1).data(), identifier.substr(1).size()); // If the identifier starts with "_", remove the underscode and return. } @@ -713,10 +749,10 @@ class Parser message << "The identifier \"" << identifier << "\" is a reserved word."; if (!context_->allow_keyword_identifiers) { - context_->log(log::LogLevel::ERROR, "EXCEPTION", message.str(), ast); + context_->log(log::LogLevel::xERROR, "EXCEPTION", message.str(), ast); throw exception(message.str(), ast); } - context_->log(log::LogLevel::INFO, "RESERVED_WORD", message.str(), ast); + context_->log(log::LogLevel::xINFO, "RESERVED_WORD", message.str(), ast); } if (scope->has_symbol(std::string(identifier.data(), identifier.size()))) @@ -725,13 +761,13 @@ class Parser message << "The identifier \"" << identifier << "\" is already used."; if (!ignore_already_used) { - context_->log(log::LogLevel::ERROR, "EXCEPTION", message.str(), ast); + context_->log(log::LogLevel::xERROR, "EXCEPTION", message.str(), ast); throw exception(message.str(), ast); } - context_->log(log::LogLevel::INFO, "ALREADY_USED", message.str(), ast); + context_->log(log::LogLevel::xINFO, "ALREADY_USED", message.str(), ast); } - context_->log(log::LogLevel::DEBUG, "RESOLVE_IDENTIFIER", + context_->log(log::LogLevel::xDEBUG, "RESOLVE_IDENTIFIER", identifier.data(), ast); return std::string(identifier.data(), identifier.size()); } @@ -788,7 +824,7 @@ class Parser // New scope outer->create_submodule(name); scope = outer->submodule(name); - context_->log(log::LogLevel::DEBUG, "MODULE_DCL", + context_->log(log::LogLevel::xDEBUG, "MODULE_DCL", "New submodule: " + scope->scope(), ast); } @@ -796,7 +832,7 @@ class Parser { // Adding to an already defined scope scope = outer->submodule(name); - context_->log(log::LogLevel::DEBUG, "MODULE_DCL", + context_->log(log::LogLevel::xDEBUG, "MODULE_DCL", "Existing submodule: " + scope->scope(), ast); } @@ -856,7 +892,7 @@ class Parser std::stringstream message; message << "Found const " << type->name() << " " << identifier << " = " << expr.to_string(); - context_->log(log::LogLevel::DEBUG, "DECLARATION", message.str(), ast); + context_->log(log::LogLevel::xDEBUG, "DECLARATION", message.str(), ast); outer->create_constant(std::string(identifier.data(), identifier.size()), expr); } @@ -892,7 +928,7 @@ class Parser { if (tag != "INTEGER_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); } int8_t value = static_cast(std::strtoll(literal.data(), nullptr, base)); data = value; @@ -902,7 +938,7 @@ class Parser { if (tag != "INTEGER_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); } uint8_t value = static_cast(std::strtoull(literal.data(), nullptr, base)); data = value; @@ -912,7 +948,7 @@ class Parser { if (tag != "INTEGER_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); } int16_t value = static_cast(std::strtoll(literal.data(), nullptr, base)); data = value; @@ -922,7 +958,7 @@ class Parser { if (tag != "INTEGER_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); } uint16_t value = static_cast(std::strtoull(literal.data(), nullptr, base)); data = value; @@ -932,7 +968,7 @@ class Parser { if (tag != "INTEGER_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); } int32_t value = static_cast(std::strtoll(literal.data(), nullptr, base)); data = value; @@ -942,7 +978,7 @@ class Parser { if (tag != "INTEGER_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); } uint32_t value = static_cast(std::strtoull(literal.data(), nullptr, base)); data = value; @@ -952,7 +988,7 @@ class Parser { if (tag != "INTEGER_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); } int64_t value = static_cast(std::strtoll(literal.data(), nullptr, base)); data = value; @@ -962,7 +998,7 @@ class Parser { if (tag != "INTEGER_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("INTEGER"), ast); } uint64_t value = static_cast(std::strtoull(literal.data(), nullptr, base)); data = value; @@ -972,7 +1008,7 @@ class Parser { if (tag != "CHAR_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("CHAR"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("CHAR"), ast); } char value = literal.at(0); data = value; @@ -982,7 +1018,7 @@ class Parser { if (tag != "WIDE_CHAR_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("WIDE_CHAR"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_CHAR"), ast); } std::u16string temp = u""; char16_t c16str[3] = u"\0"; @@ -1001,7 +1037,7 @@ class Parser { if (tag != "WIDE_CHAR_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("WIDE_CHAR"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_CHAR"), ast); } using convert_type = std::codecvt_utf8; std::wstring_convert converter; @@ -1021,7 +1057,7 @@ class Parser if (tag != "STRING_LITERAL"_ && tag != "UNEXPECTED_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "STRING", message("STRING"), ast); + context_->log(log::LogLevel::xWARNING, "STRING", message("STRING"), ast); } data = aux; @@ -1038,7 +1074,7 @@ class Parser if (tag != "WIDE_STRING_LITERAL"_ && tag != "WIDE_SUBSTRING_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("WIDE_STRING"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_STRING"), ast); } using convert_type = std::codecvt_utf8; std::wstring_convert converter; @@ -1065,7 +1101,7 @@ class Parser { if (tag != "BOOLEAN_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("BOOLEAN"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("BOOLEAN"), ast); } if (literal == "TRUE") { @@ -1080,7 +1116,7 @@ class Parser std::stringstream message; message << "Expected bool value (TRUE or FALSE) but found '" << literal << "'. It will be take the value 'FALSE'."; - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message.str(), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message.str(), ast); data = false; } break; @@ -1089,7 +1125,7 @@ class Parser { if (tag != "FLOAT_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("FLOAT"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("FLOAT"), ast); } float value = std::stof(literal.data(), nullptr); data = value; @@ -1099,7 +1135,7 @@ class Parser { if (tag != "FLOAT_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("FLOAT"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("FLOAT"), ast); } double value = std::stod(literal.data(), nullptr); data = value; @@ -1109,14 +1145,14 @@ class Parser { if (tag != "FLOAT_LITERAL"_) { - context_->log(log::LogLevel::WARNING, "UNEXPECTED_LITERAL", message("FLOAT"), ast); + context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("FLOAT"), ast); } long double value = std::stold(literal.data(), nullptr); data = value; break; } default: - context_->log(log::LogLevel::ERROR, "UNEXPECTED_LITERAL_TYPE", + context_->log(log::LogLevel::xERROR, "UNEXPECTED_LITERAL_TYPE", message(data.type().name().c_str()), ast); return false; } @@ -1253,14 +1289,14 @@ class Parser const auto& name_view = ast->nodes[0]->token; const std::string name(name_view.data(), name_view.size()); EnumerationType result(name); // TODO: Support other Enum types?, the grammar should be upgraded. - context_->log(log::LogLevel::DEBUG, "ENUM_DCL", + context_->log(log::LogLevel::xDEBUG, "ENUM_DCL", "Found enum \"" + name + "\"", ast); for (size_t idx = 1; idx < ast->nodes.size(); ++idx) { const auto& token_view = ast->nodes[idx]->token; const std::string token(token_view.data(), token_view.size()); - context_->log(log::LogLevel::DEBUG, "ENUM_DCL_VALUE", + context_->log(log::LogLevel::xDEBUG, "ENUM_DCL_VALUE", "Adding \"" + token + "\" to enum \"" + name + "\"", ast); result.add_enumerator(token); @@ -1284,12 +1320,12 @@ class Parser { std::stringstream message; message << "Struct " << ast->token << " was already declared."; - context_->log(log::LogLevel::ERROR, "EXCEPTION", message.str(), ast); + context_->log(log::LogLevel::xERROR, "EXCEPTION", message.str(), ast); throw exception(message.str(), ast); } StructType result(name); - context_->log(log::LogLevel::DEBUG, "STRUCT_FW_DCL", + context_->log(log::LogLevel::xDEBUG, "STRUCT_FW_DCL", "Found forward struct declaration: \"" + name + "\"", ast); outer->structure(std::move(result)); @@ -1305,7 +1341,7 @@ class Parser { std::stringstream message; message << "Union " << ast->token << " was already declared."; - context_->log(log::LogLevel::ERROR, "EXCEPTION", message.str(), ast); + context_->log(log::LogLevel::xERROR, "EXCEPTION", message.str(), ast); throw exception(message.str(), ast); } @@ -1313,7 +1349,7 @@ class Parser // Union forward declaration may be an special case of Union, // because they doesn't defines the switch type StructType result(name); - context_->log(log::LogLevel::DEBUG, "UNION_FW_DCL", + context_->log(log::LogLevel::xDEBUG, "UNION_FW_DCL", "Found forward union declaration: \"" + name + "\"", ast); outer->structure(std::move(result)); @@ -1348,7 +1384,7 @@ class Parser std::stringstream message; message << "Struct \"" << name << "\" cannot inherit from \"" << node->token.data() << "\": Struct was not found."; - context_->log(log::LogLevel::ERROR, "STRUCT_DEF", message.str(), ast); + context_->log(log::LogLevel::xERROR, "STRUCT_DEF", message.str(), ast); throw exception(message.str(), ast); } break; @@ -1371,17 +1407,17 @@ class Parser const std::string msg = "Struct \"" + name + "\" redefinition."; if (context_->ignore_redefinition) { - context_->log(log::LogLevel::INFO, "REDEFINITION", + context_->log(log::LogLevel::xINFO, "REDEFINITION", msg, ast); return; } - context_->log(log::LogLevel::ERROR, "EXCEPTION", + context_->log(log::LogLevel::xERROR, "EXCEPTION", msg, ast); throw exception(msg, ast); } - context_->log(log::LogLevel::DEBUG, "STRUCT_DEF", + context_->log(log::LogLevel::xDEBUG, "STRUCT_DEF", "Struct \"" + name + "\" definition.", ast); @@ -1395,7 +1431,7 @@ class Parser for (auto& member : member_list) { - context_->log(log::LogLevel::DEBUG, "STRUCT_DEF_MEMBER", + context_->log(log::LogLevel::xDEBUG, "STRUCT_DEF_MEMBER", "Struct \"" + name + "\" member: {" + member.name() + ": " + member.type().name() + "}", ast); struct_type->add_member(std::move(member)); @@ -1439,23 +1475,23 @@ class Parser const std::string msg = "Union \"" + name + "\" redefinition."; if (context_->ignore_redefinition) { - context_->log(log::LogLevel::INFO, "REDEFINITION", + context_->log(log::LogLevel::xINFO, "REDEFINITION", msg, ast); return; } - context_->log(log::LogLevel::ERROR, "EXCEPTION", + context_->log(log::LogLevel::xERROR, "EXCEPTION", msg, ast); throw exception(msg, ast); } - context_->log(log::LogLevel::DEBUG, "UNION_DEF", + context_->log(log::LogLevel::xDEBUG, "UNION_DEF", "Union \"" + name + "\" definition.", ast); for (auto& pair : member_list) { Member& member = pair.second; - context_->log(log::LogLevel::DEBUG, "UNION_DEF_MEMBER", + context_->log(log::LogLevel::xDEBUG, "UNION_DEF_MEMBER", "Union \"" + name + "\" member: " + member.name(), ast); union_type.add_case_member(pair.first, std::move(member)); @@ -1480,7 +1516,7 @@ class Parser } default: { - context_->log(log::LogLevel::ERROR, "UNSUPPORTED", + context_->log(log::LogLevel::xERROR, "UNSUPPORTED", "Found unexepcted node \"" + node->name + "\" while parsing an Union. Ignoring.", node); } @@ -1570,7 +1606,7 @@ class Parser { std::stringstream message; message << "Member identifier " << ast->token << " already defined"; - context_->log(log::LogLevel::ERROR, "EXCEPTION", message.str(), ast); + context_->log(log::LogLevel::xERROR, "EXCEPTION", message.str(), ast); throw exception(message.str(), ast); } if (dimensions.empty()) @@ -1614,7 +1650,7 @@ class Parser } } - context_->log(log::LogLevel::WARNING, "UNSUPPORTED", + context_->log(log::LogLevel::xWARNING, "UNSUPPORTED", "Found \"@annotation " + name + "\" but annotations aren't supported. Ignoring.", ast); /* TODO @@ -1663,7 +1699,7 @@ class Parser } } - context_->log(log::LogLevel::WARNING, "UNSUPPORTED", + context_->log(log::LogLevel::xWARNING, "UNSUPPORTED", "Found \"bitset " + name + "\" but bitsets aren't supported. Ignoring.", ast); /* TODO @@ -1708,7 +1744,7 @@ class Parser } } - context_->log(log::LogLevel::WARNING, "UNSUPPORTED", + context_->log(log::LogLevel::xWARNING, "UNSUPPORTED", "Found \"bitmask " + name + "\" but bitmasks aren't supported. Ignoring.", ast); /* TODO @@ -1764,7 +1800,7 @@ class Parser DynamicType::Ptr type = outer->type(token); if (type.get() == nullptr) { - context_->log(log::LogLevel::ERROR, "EXCEPTION", + context_->log(log::LogLevel::xERROR, "EXCEPTION", "Member type " + token + " is unknown", node); throw exception("Member type " + token + " is unknown", node); @@ -1886,7 +1922,7 @@ class Parser return type_spec(node, outer); } - context_->log(log::LogLevel::ERROR, "UNKNOWN_TYPE", + context_->log(log::LogLevel::xERROR, "UNKNOWN_TYPE", token, node); @@ -1927,7 +1963,7 @@ class Parser dim = c_data.value(); break; default: - context_->log(log::LogLevel::ERROR, "EXCEPTION", + context_->log(log::LogLevel::xERROR, "EXCEPTION", "Only a positive integer number can be used as dimension.", node); throw exception("Only a positive integer number can be used as dimension.", node); @@ -2015,7 +2051,7 @@ class Parser { std::stringstream message; message << "Member identifier " << ast->token << " already defined"; - context_->log(log::LogLevel::ERROR, "EXCEPTION", message.str(), ast); + context_->log(log::LogLevel::xERROR, "EXCEPTION", message.str(), ast); throw exception(message.str(), ast); } if (dimensions.empty()) @@ -2114,7 +2150,7 @@ class Parser dim = c_data.value(); break; default: - context_->log(log::LogLevel::ERROR, "EXCEPTION", + context_->log(log::LogLevel::xERROR, "EXCEPTION", "Only a positive intenger number can be used as dimension.", node); throw exception("Only a positive intenger number can be used as dimension.", node); diff --git a/test/unitary/parser/parser_test.cpp b/test/unitary/parser/parser_test.cpp index 82cbbe7d..55dc0ded 100644 --- a/test/unitary/parser/parser_test.cpp +++ b/test/unitary/parser/parser_test.cpp @@ -1000,7 +1000,7 @@ TEST (IDLParser, enumerations_test) TEST (IDLParser, bad_idl_logging) { Context context; - context.log_level(log::LogLevel::DEBUG); + context.log_level(log::LogLevel::xDEBUG); // context.print_log(true); // Useful for debbuging context.preprocess = false; parse(R"~~( @@ -1055,7 +1055,7 @@ TEST (IDLParser, bad_idl_logging) TEST (IDLParser, logging) { Context context; - context.log_level(log::LogLevel::INFO); + context.log_level(log::LogLevel::xINFO); // context.print_log(true); // Useful for debbuging context.preprocess = false; context.allow_keyword_identifiers = true; @@ -1163,7 +1163,7 @@ TEST (IDLParser, logging) #define EXPECTED_LOG_RESULTS_FILTERED(LOG_LEVEL, N_ENTRIES, ASSERT, PRINT) \ { \ Context context; \ - context.log_level(log::LogLevel::DEBUG); \ + context.log_level(log::LogLevel::xDEBUG); \ if (PRINT) \ { \ context.print_log(true); \ @@ -1190,14 +1190,14 @@ TEST (IDLParser, severity_logging) const boolean BAD_LITERAL = 55; // DEBUG + WARNING + WARNING + DEBUG (result) )~~"; - EXPECTED_LOG_RESULTS(ERROR, 1, ASSERT_EQ, false); - EXPECTED_LOG_RESULTS(WARNING, 3, ASSERT_EQ, false); - EXPECTED_LOG_RESULTS(INFO, 4, ASSERT_EQ, false); - EXPECTED_LOG_RESULTS(DEBUG, 11, ASSERT_EQ, false); - EXPECTED_LOG_RESULTS_FILTERED(ERROR, 1, ASSERT_EQ, false); - EXPECTED_LOG_RESULTS_FILTERED(WARNING, 2, ASSERT_EQ, false); - EXPECTED_LOG_RESULTS_FILTERED(INFO, 1, ASSERT_EQ, false); - EXPECTED_LOG_RESULTS_FILTERED(DEBUG, 7, ASSERT_EQ, false); + EXPECTED_LOG_RESULTS(xERROR, 1, ASSERT_EQ, false); + EXPECTED_LOG_RESULTS(xWARNING, 3, ASSERT_EQ, false); + EXPECTED_LOG_RESULTS(xINFO, 4, ASSERT_EQ, false); + EXPECTED_LOG_RESULTS(xDEBUG, 11, ASSERT_EQ, false); + EXPECTED_LOG_RESULTS_FILTERED(xERROR, 1, ASSERT_EQ, false); + EXPECTED_LOG_RESULTS_FILTERED(xWARNING, 2, ASSERT_EQ, false); + EXPECTED_LOG_RESULTS_FILTERED(xINFO, 1, ASSERT_EQ, false); + EXPECTED_LOG_RESULTS_FILTERED(xDEBUG, 7, ASSERT_EQ, false); } TEST(IDLParser, alias_test) diff --git a/test/unitary/xtypes/primitive_types.cpp b/test/unitary/xtypes/primitive_types.cpp index 991a4063..8e9a398a 100644 --- a/test/unitary/xtypes/primitive_types.cpp +++ b/test/unitary/xtypes/primitive_types.cpp @@ -19,18 +19,18 @@ using namespace eprosima::xtypes; -static const uint8_t UINT8 = 250; -static const int16_t INT16 = -32760; -static const uint16_t UINT16 = 65530; -static const int32_t INT32 = -2147483640; -static const uint32_t UINT32 = 4294967290; -static const int64_t INT64 = -9223372036854775800; -static const uint64_t UINT64 = 18446744073709551610ULL; -static const float FLOAT = 3.1415927410125732421875f; -static const double DOUBLE = 3.1415926535897931159979631875; -static const char CHAR = 'f'; -static const char16_t CHAR16 = '\u00f1'; -static const wchar_t WCHAR = 34590; +static const uint8_t xUINT8 = 250; +static const int16_t xINT16 = -32760; +static const uint16_t xUINT16 = 65530; +static const int32_t xINT32 = -2147483640; +static const uint32_t xUINT32 = 4294967290; +static const int64_t xINT64 = -9223372036854775800; +static const uint64_t xUINT64 = 18446744073709551610ULL; +static const float xFLOAT = 3.1415927410125732421875f; +static const double xDOUBLE = 3.1415926535897931159979631875; +static const char xCHAR = 'f'; +static const char16_t xCHAR16 = '\u00f1'; +static const wchar_t xWCHAR = 34590; /********************************************* * DynamicType Primitive Tests * @@ -80,7 +80,7 @@ TEST (PrimitiveTypes, primitive_type_uint8) EXPECT_TRUE(singleCheck(15, 15)); EXPECT_FALSE(singleCheck(15, 16)); EXPECT_TRUE(singleCheck(-1, 255)); - assignCheck(UINT8); + assignCheck(xUINT8); } TEST (PrimitiveTypes, primitive_type_uint16) @@ -88,7 +88,7 @@ TEST (PrimitiveTypes, primitive_type_uint16) EXPECT_TRUE(singleCheck(1500, 1500)); EXPECT_FALSE(singleCheck(1500, 1501)); EXPECT_TRUE(singleCheck(-1, 0xFFFF)); - assignCheck(UINT16); + assignCheck(xUINT16); } TEST (PrimitiveTypes, primitive_type_int16) @@ -97,7 +97,7 @@ TEST (PrimitiveTypes, primitive_type_int16) EXPECT_FALSE(singleCheck(1500, -1500)); EXPECT_FALSE(singleCheck(1500, 1501)); EXPECT_TRUE(singleCheck(-1, int16_t(0xFFFF))); - assignCheck(INT16); + assignCheck(xINT16); } TEST (PrimitiveTypes, primitive_type_uint32) @@ -105,7 +105,7 @@ TEST (PrimitiveTypes, primitive_type_uint32) EXPECT_TRUE(singleCheck(150000, 150000)); EXPECT_FALSE(singleCheck(150000, 150001)); EXPECT_TRUE(singleCheck(std::numeric_limits::max(), 0xFFFFFFFF)); - assignCheck(UINT32); + assignCheck(xUINT32); } TEST (PrimitiveTypes, primitive_type_int32) @@ -114,7 +114,7 @@ TEST (PrimitiveTypes, primitive_type_int32) EXPECT_FALSE(singleCheck(-150000, 150000)); EXPECT_FALSE(singleCheck(150000, 150001)); EXPECT_TRUE(singleCheck(-1, 0xFFFFFFFF)); - assignCheck(INT32); + assignCheck(xINT32); } TEST (PrimitiveTypes, primitive_type_uint64) @@ -122,7 +122,7 @@ TEST (PrimitiveTypes, primitive_type_uint64) EXPECT_TRUE(singleCheck(15000000000, 15000000000)); EXPECT_FALSE(singleCheck(15000000000, 15000000001)); EXPECT_TRUE(singleCheck(-1, 0xFFFFFFFFFFFFFFFF)); - assignCheck(UINT64); + assignCheck(xUINT64); } TEST (PrimitiveTypes, primitive_type_int64) @@ -131,21 +131,21 @@ TEST (PrimitiveTypes, primitive_type_int64) EXPECT_FALSE(singleCheck(-15000000000, 15000000000)); EXPECT_FALSE(singleCheck(15000000000, 15000000001)); EXPECT_TRUE(singleCheck(-1, 0xFFFFFFFFFFFFFFFF)); - assignCheck(INT64); + assignCheck(xINT64); } TEST (PrimitiveTypes, primitive_type_float) { EXPECT_TRUE(singleCheck(54.5f, 54.5f)); EXPECT_FALSE(singleCheck(5.56f, 5.55f)); - assignCheck(FLOAT); + assignCheck(xFLOAT); } TEST (PrimitiveTypes, primitive_type_double) { EXPECT_TRUE(singleCheck(5.55e40, 5.55e40)); EXPECT_FALSE(singleCheck(5.550000001e40, 5.55e40)); - assignCheck(DOUBLE); + assignCheck(xDOUBLE); } // TEST (PrimitiveTypes, primitive_type_longdouble) moved to no_memcheck_tests.cpp @@ -155,21 +155,21 @@ TEST (PrimitiveTypes, primitive_type_char) EXPECT_TRUE(singleCheck('a', 'a')); EXPECT_FALSE(singleCheck('a', 'b')); EXPECT_TRUE((singleCheck('a', 'a'))); - assignCheck(CHAR); + assignCheck(xCHAR); } TEST (PrimitiveTypes, primitive_type_wchar) { EXPECT_TRUE(singleCheck(L'a', L'a')); EXPECT_FALSE(singleCheck(L'a', L'b')); - assignCheck(WCHAR); + assignCheck(xWCHAR); } TEST (PrimitiveTypes, primitive_type_char16) { EXPECT_TRUE(singleCheck(u'a', u'a')); EXPECT_FALSE(singleCheck(u'a', u'b')); - assignCheck(CHAR16); + assignCheck(xCHAR16); } TEST (PrimitiveTypes, primitive_type_double_longdouble) diff --git a/test/unitary/xtypes/struct_type.cpp b/test/unitary/xtypes/struct_type.cpp index a51165fa..ef568267 100644 --- a/test/unitary/xtypes/struct_type.cpp +++ b/test/unitary/xtypes/struct_type.cpp @@ -24,19 +24,19 @@ using namespace std; using namespace eprosima::xtypes; -static const uint8_t UINT8 = 250; -static const int16_t INT16 = -32760; -static const uint16_t UINT16 = 65530; -static const int32_t INT32 = -2147483640; -static const uint32_t UINT32 = 4294967290; -static const int64_t INT64 = -9223372036854775800; -static const uint64_t UINT64 = 18446744073709551610ULL; -static const float FLOAT = 3.1415927410125732421875f; -static const double DOUBLE = 3.1415926535897931159979631875; -static const long double LDOUBLE = 3.14159265358979321159979631875l; -static const char CHAR = 'f'; -static const char16_t CHAR16 = '\u00f1'; -static const wchar_t WCHAR = 34590; +static const uint8_t xUINT8 = 250; +static const int16_t xINT16 = -32760; +static const uint16_t xUINT16 = 65530; +static const int32_t xINT32 = -2147483640; +static const uint32_t xUINT32 = 4294967290; +static const int64_t xINT64 = -9223372036854775800; +static const uint64_t xUINT64 = 18446744073709551610ULL; +static const float xFLOAT = 3.1415927410125732421875f; +static const double xDOUBLE = 3.1415926535897931159979631875; +static const long double xLDOUBLE = 3.14159265358979321159979631875l; +static const char xCHAR = 'f'; +static const char16_t xCHAR16 = '\u00f1'; +static const wchar_t xWCHAR = 34590; static const std::string INNER_STRING_VALUE = "lay_down_and_cry"; static const std::string INNER_SEQUENCE_STRING = "another_prick_in_the_wall"; @@ -227,35 +227,35 @@ TEST (StructType, type_verify_test) DynamicData d(st); d["bool"].value(true); - d["uint8_t"].value(UINT8); - d["int16_t"].value(INT16); - d["uint16_t"].value(UINT16); - d["int32_t"].value(INT32); - d["uint32_t"].value(UINT32); - d["int64_t"].value(INT64); - d["uint64_t"].value(UINT64); - d["float"].value(FLOAT); - d["double"].value(DOUBLE); - d["long double"].value(LDOUBLE); - d["char"].value(CHAR); - d["char16_t"].value(CHAR16); - d["wchar_t"].value(WCHAR); + d["uint8_t"].value(xUINT8); + d["int16_t"].value(xINT16); + d["uint16_t"].value(xUINT16); + d["int32_t"].value(xINT32); + d["uint32_t"].value(xUINT32); + d["int64_t"].value(xINT64); + d["uint64_t"].value(xUINT64); + d["float"].value(xFLOAT); + d["double"].value(xDOUBLE); + d["long double"].value(xLDOUBLE); + d["char"].value(xCHAR); + d["char16_t"].value(xCHAR16); + d["wchar_t"].value(xWCHAR); EXPECT_EQ(true, d["bool"].value()); - EXPECT_EQ(UINT8, d["uint8_t"].value()); - EXPECT_EQ(INT16, d["int16_t"].value()); - EXPECT_EQ(UINT16, d["uint16_t"].value()); - EXPECT_EQ(INT32, d["int32_t"].value()); - EXPECT_EQ(UINT32, d["uint32_t"].value()); - EXPECT_EQ(INT64, d["int64_t"].value()); - EXPECT_EQ(UINT64, d["uint64_t"].value()); - EXPECT_EQ( float(FLOAT), d["float"].value()); - EXPECT_EQ( double(DOUBLE), d["double"].value()); - long double ld = LDOUBLE; + EXPECT_EQ(xUINT8, d["uint8_t"].value()); + EXPECT_EQ(xINT16, d["int16_t"].value()); + EXPECT_EQ(xUINT16, d["uint16_t"].value()); + EXPECT_EQ(xINT32, d["int32_t"].value()); + EXPECT_EQ(xUINT32, d["uint32_t"].value()); + EXPECT_EQ(xINT64, d["int64_t"].value()); + EXPECT_EQ(xUINT64, d["uint64_t"].value()); + EXPECT_EQ( float(xFLOAT), d["float"].value()); + EXPECT_EQ( double(xDOUBLE), d["double"].value()); + long double ld = xLDOUBLE; EXPECT_EQ( ld, d["long double"].value()); - EXPECT_EQ( CHAR, d["char"].value()); - EXPECT_EQ( CHAR16, d["char16_t"].value()); - EXPECT_EQ( WCHAR, d["wchar_t"].value()); + EXPECT_EQ( xCHAR, d["char"].value()); + EXPECT_EQ( xCHAR16, d["char16_t"].value()); + EXPECT_EQ( xWCHAR, d["wchar_t"].value()); } @@ -334,35 +334,35 @@ DynamicData create_dynamic_data( DynamicData the_data(the_struct); the_data["bool"] = true; - the_data["uint8_t"] = UINT8; - the_data["int16_t"] = INT16; - the_data["uint16_t"] = UINT16; - the_data["int32_t"] = INT32; - the_data["uint32_t"] = UINT32; - the_data["int64_t"] = INT64; - the_data["uint64_t"] = UINT64; - the_data["float"] = FLOAT; - the_data["double"] = DOUBLE; - the_data["long_double"] = LDOUBLE; + the_data["uint8_t"] = xUINT8; + the_data["int16_t"] = xINT16; + the_data["uint16_t"] = xUINT16; + the_data["int32_t"] = xINT32; + the_data["uint32_t"] = xUINT32; + the_data["int64_t"] = xINT64; + the_data["uint64_t"] = xUINT64; + the_data["float"] = xFLOAT; + the_data["double"] = xDOUBLE; + the_data["long_double"] = xLDOUBLE; for (int i = 0; i < STRUCTS_SIZE; ++i) // creating "sequence" { DynamicData tmp_data(inner_struct); tmp_data["inner_string"] = INNER_STRING_VALUE; - tmp_data["inner_float"].value(FLOAT); + tmp_data["inner_float"].value(xFLOAT); add_seq_data(tmp_data["inner_sequence_string"], STRUCTS_SIZE, INNER_SEQUENCE_STRING); for (int j = 0; j < STRUCTS_SIZE; ++j) // creating "sequence.inner_sequence_struct" { DynamicData tmp_inner_data(second_inner_struct); tmp_inner_data["second_inner_string"] = SECOND_INNER_STRING; - tmp_inner_data["second_inner_uint32_t"] = UINT32; - add_array_data(tmp_inner_data["second_inner_array"], STRUCTS_SIZE, UINT8); + tmp_inner_data["second_inner_uint32_t"] = xUINT32; + add_array_data(tmp_inner_data["second_inner_array"], STRUCTS_SIZE, xUINT8); tmp_data["inner_sequence_struct"].push(tmp_inner_data); } for (int j = 0; j < STRUCTS_SIZE; ++j) { - add_array_data(the_data["array"][j], STRUCTS_SIZE, LDOUBLE); + add_array_data(the_data["array"][j], STRUCTS_SIZE, xLDOUBLE); } the_data["sequence"].push(tmp_data); } @@ -378,36 +378,36 @@ TEST (StructType, complex_and_member_access) DynamicData the_data = create_dynamic_data(the_struct, inner_struct, second_inner_struct); - EXPECT_EQ(UINT32, the_data["uint32_t"].value()); - EXPECT_EQ(INT32, the_data["int32_t"].value()); - EXPECT_EQ(UINT16, the_data["uint16_t"].value()); - EXPECT_EQ(INT16, the_data["int16_t"].value()); + EXPECT_EQ(xUINT32, the_data["uint32_t"].value()); + EXPECT_EQ(xINT32, the_data["int32_t"].value()); + EXPECT_EQ(xUINT16, the_data["uint16_t"].value()); + EXPECT_EQ(xINT16, the_data["int16_t"].value()); EXPECT_EQ(true, the_data["bool"].value()); - EXPECT_EQ(UINT8, the_data["uint8_t"].value()); - EXPECT_EQ(INT64, the_data["int64_t"].value()); - EXPECT_EQ(UINT64, the_data["uint64_t"].value()); - EXPECT_EQ(FLOAT, the_data["float"].value()); - EXPECT_EQ(DOUBLE, the_data["double"].value()); - EXPECT_EQ(LDOUBLE, the_data["long_double"].value()); + EXPECT_EQ(xUINT8, the_data["uint8_t"].value()); + EXPECT_EQ(xINT64, the_data["int64_t"].value()); + EXPECT_EQ(xUINT64, the_data["uint64_t"].value()); + EXPECT_EQ(xFLOAT, the_data["float"].value()); + EXPECT_EQ(xDOUBLE, the_data["double"].value()); + EXPECT_EQ(xLDOUBLE, the_data["long_double"].value()); EXPECT_EQ(true, the_data[0].value()); - EXPECT_EQ(UINT8, the_data[1].value()); - EXPECT_EQ(INT16, the_data[2].value()); - EXPECT_EQ(UINT16, the_data[3].value()); - EXPECT_EQ(INT32, the_data[4].value()); - EXPECT_EQ(UINT32, the_data[5].value()); - EXPECT_EQ(INT64, the_data[6].value()); - EXPECT_EQ(UINT64, the_data[7].value()); - EXPECT_EQ(FLOAT, the_data[8].value()); - EXPECT_EQ(DOUBLE, the_data[9].value()); - EXPECT_EQ(LDOUBLE, the_data[10].value()); + EXPECT_EQ(xUINT8, the_data[1].value()); + EXPECT_EQ(xINT16, the_data[2].value()); + EXPECT_EQ(xUINT16, the_data[3].value()); + EXPECT_EQ(xINT32, the_data[4].value()); + EXPECT_EQ(xUINT32, the_data[5].value()); + EXPECT_EQ(xINT64, the_data[6].value()); + EXPECT_EQ(xUINT64, the_data[7].value()); + EXPECT_EQ(xFLOAT, the_data[8].value()); + EXPECT_EQ(xDOUBLE, the_data[9].value()); + EXPECT_EQ(xLDOUBLE, the_data[10].value()); for (size_t i = 0; i < STRUCTS_SIZE; ++i) { EXPECT_EQ(the_data["sequence"][i]["inner_string"].value(), INNER_STRING_VALUE); EXPECT_EQ(the_data[12][i][0].value(), INNER_STRING_VALUE); - EXPECT_EQ(the_data["sequence"][i]["inner_float"].value(), FLOAT); - EXPECT_EQ(the_data[12][i][1].value(), FLOAT); + EXPECT_EQ(the_data["sequence"][i]["inner_float"].value(), xFLOAT); + EXPECT_EQ(the_data[12][i][1].value(), xFLOAT); check_collection_data(the_data["sequence"][i]["inner_sequence_string"], STRUCTS_SIZE, INNER_SEQUENCE_STRING); check_collection_data(the_data[12][i][2], STRUCTS_SIZE, INNER_SEQUENCE_STRING); @@ -419,21 +419,21 @@ TEST (StructType, complex_and_member_access) SECOND_INNER_STRING); EXPECT_EQ( the_data["sequence"][i]["inner_sequence_struct"][j]["second_inner_uint32_t"].value(), - UINT32); + xUINT32); EXPECT_EQ( the_data[12][i][3][j][0].value(), SECOND_INNER_STRING); EXPECT_EQ( the_data[12][i][3][j][1].value(), - UINT32); + xUINT32); check_collection_data(the_data["sequence"][i]["inner_sequence_struct"][j]["second_inner_array"], - STRUCTS_SIZE, UINT8); - check_collection_data(the_data[12][i][3][j][2], STRUCTS_SIZE, UINT8); + STRUCTS_SIZE, xUINT8); + check_collection_data(the_data[12][i][3][j][2], STRUCTS_SIZE, xUINT8); } - check_collection_data(the_data["array"][i], STRUCTS_SIZE, LDOUBLE); - check_collection_data(the_data[11][i], STRUCTS_SIZE, LDOUBLE); + check_collection_data(the_data["array"][i], STRUCTS_SIZE, xLDOUBLE); + check_collection_data(the_data[11][i], STRUCTS_SIZE, xLDOUBLE); } } diff --git a/tools/idl_validator.cpp b/tools/idl_validator.cpp index a281c292..e5b36826 100644 --- a/tools/idl_validator.cpp +++ b/tools/idl_validator.cpp @@ -17,7 +17,7 @@ int main( std::string idl_spec = argv[1]; std::cout << "IDL: " << idl_spec << std::endl; idl::Context context; - context.log_level(idl::log::LogLevel::DEBUG); + context.log_level(idl::log::LogLevel::xDEBUG); context.print_log(true); context.ignore_redefinition = true; context = idl::parse(idl_spec, context); From 8ac4da907c745d1ff1977772b2823f8367f04401 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 13 Jan 2023 11:33:40 +0100 Subject: [PATCH 18/49] Refs 16497. Fixing testing if xtypes exceptions are disabled Signed-off-by: Miguel Barro --- test/unitary/xtypes/dynamicdata_operators.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/unitary/xtypes/dynamicdata_operators.cpp b/test/unitary/xtypes/dynamicdata_operators.cpp index 50a94018..a13e5216 100644 --- a/test/unitary/xtypes/dynamicdata_operators.cpp +++ b/test/unitary/xtypes/dynamicdata_operators.cpp @@ -316,11 +316,15 @@ TEST (DynamicDataOperators, arithmetic_binary_operators) check_arithmetic_int_binary_operators(20u, 2u); check_arithmetic_int_binary_operators(-6, -2); check_arithmetic_int_binary_operators(60u, 2u); + +#ifdef XTYPES_EXCEPTIONS // Operators not available check_arithmetic_int_binary_operators(true, false, true); check_arithmetic_int_binary_operators('a', 'b', true); check_arithmetic_int_binary_operators('\n', 'b', true); check_arithmetic_int_binary_operators('\u00f1', 'b', true); +#endif + // Operators available (only floating-point) check_arithmetic_flt_binary_operators(PI, 1.5f); check_arithmetic_flt_binary_operators(PI_D, 1.5); From 7f1461d879367751af0b205dc675b142bf0462cf Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 13 Jan 2023 12:32:35 +0100 Subject: [PATCH 19/49] Refs 16497. Forcing current workding dir as preprocessor include path. Signed-off-by: Miguel Barro --- include/xtypes/idl/parser.hpp | 2 +- test/unitary/parser/parser_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index a07bd128..ca2bf987 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -58,7 +58,7 @@ // define preprocessor strategy #ifdef _MSC_VER -# define EPROSIMA_PLATFORM_PREPROCESSOR "cl /EP" +# define EPROSIMA_PLATFORM_PREPROCESSOR "cl /EP /I." # define EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY preprocess_strategy::temporary_file # define EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES "/I" # define EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR " 2>nul" diff --git a/test/unitary/parser/parser_test.cpp b/test/unitary/parser/parser_test.cpp index 55dc0ded..50c1258f 100644 --- a/test/unitary/parser/parser_test.cpp +++ b/test/unitary/parser/parser_test.cpp @@ -764,7 +764,7 @@ TEST (IDLParser, include_from_string) }; )"); std::map result = context.module().get_all_types(); - EXPECT_EQ(2, result.size()); + ASSERT_EQ(2, result.size()); const DynamicType* my_struct = result["Test00"].get(); DynamicData data(*my_struct); ASSERT_EQ(data["incl"]["my_string"].type().name(), "std::string"); From 25222344369d66ee8dcffd0224533c1b2d1df093 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 13 Jan 2023 13:19:26 +0100 Subject: [PATCH 20/49] Refs 16497. Fixing windows type size on tests literals Signed-off-by: Miguel Barro --- include/xtypes/DynamicData.hpp | 3 ++- test/unitary/parser/parser_test.cpp | 4 ++++ test/unitary/xtypes/collection_types.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/xtypes/DynamicData.hpp b/include/xtypes/DynamicData.hpp index 907255b7..b6dc1ac6 100644 --- a/include/xtypes/DynamicData.hpp +++ b/include/xtypes/DynamicData.hpp @@ -979,7 +979,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef || (type_.kind() == PrimitiveTypeKindTrait::kind) || (type_.is_enumerated_type()), "Expected type '" << type_.name() - << "' but '" << PrimitiveTypeKindTrait::name << "' received while setting value."); + << "' but '" << PrimitiveTypeKindTrait::name << "' received while setting value.", + true); if (type_.is_enumerated_type()) { diff --git a/test/unitary/parser/parser_test.cpp b/test/unitary/parser/parser_test.cpp index 50c1258f..787080b8 100644 --- a/test/unitary/parser/parser_test.cpp +++ b/test/unitary/parser/parser_test.cpp @@ -1323,7 +1323,11 @@ TEST (IDLParser, union_tests) EXPECT_EQ(data["union_c"].d().value(), 2); data["union_c"].d(3); EXPECT_EQ(data["union_c"].d().value(), 3); +#ifdef _MSC_VER + data["union_c"]["my_uint64"] = 314ull; +#else data["union_c"]["my_uint64"] = 314ul; +#endif // _MSC_VER EXPECT_EQ(data["union_c"].d().value(), 1); data["union_c"]["my_int32"] = 314; EXPECT_EQ(data["union_c"].d().value(), 0); diff --git a/test/unitary/xtypes/collection_types.cpp b/test/unitary/xtypes/collection_types.cpp index fe858280..0bb37e8d 100644 --- a/test/unitary/xtypes/collection_types.cpp +++ b/test/unitary/xtypes/collection_types.cpp @@ -169,11 +169,11 @@ TEST (CollectionTypes, primitive_arrays) check_primitive_array(25000000000); check_primitive_array(250.76653); check_primitive_array(250.76653e40); -#ifdef WIN32 +#ifdef _MSC_VER check_primitive_array(1.797e308L); #else check_primitive_array(250.76653e1000l); -#endif // WIN32 +#endif // _MSC_VER check_primitive_array('L'); check_primitive_array(L'G'); } @@ -437,11 +437,11 @@ TEST (CollectionTypes, primitive_sequences) check_primitive_seq(25000000000); check_primitive_seq(250.76653); check_primitive_seq(250.76653e40); -#ifdef WIN32 +#ifdef _MSC_VER check_primitive_seq(1.79e308l); #else check_primitive_seq(250.76653e1000l); -#endif // WIN32 +#endif // _MSC_VER check_primitive_seq('L'); check_primitive_seq(L'G'); } From 2576179c9289eafd4b8297c4601ee219359c2e3f Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 13 Jan 2023 14:01:53 +0100 Subject: [PATCH 21/49] Refs 16497. Match preprocessor and build platform and add copyright. Signed-off-by: Miguel Barro --- CMakeLists.txt | 14 ++++++++++++++ test/environment.ps1 | 32 +++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c696fb8..324ca56e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,8 +196,22 @@ if(XTYPES_BUILD_TESTS) # if preprocessor is already available not populate if(NOT CL_BIN) + + set(PREPROCESS_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM}) + set(PREPROCESS_GENERATOR_TOOLSET ${CMAKE_GENERATOR_TOOLSET}) + + if(NOT CMAKE_GENERATOR_PLATFORM) + set(PREPROCESS_GENERATOR_PLATFORM x64) + endif() + + if(NOT CMAKE_GENERATOR_TOOLSET) + set(PREPROCESS_GENERATOR_TOOLSET x64,host=x64) + endif() + execute_process( COMMAND powershell -File "${CMAKE_CURRENT_LIST_DIR}\\test\\environment.ps1" + -Platform ${PREPROCESS_GENERATOR_PLATFORM} + -Toolset ${PREPROCESS_GENERATOR_TOOLSET} OUTPUT_VARIABLE MSVC_TEST_PROPERTIES) endif() diff --git a/test/environment.ps1 b/test/environment.ps1 index a9898bd4..c79f0a78 100644 --- a/test/environment.ps1 +++ b/test/environment.ps1 @@ -1,3 +1,28 @@ +# Copyright 2023 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 environment.ps1 +# + +Param( +[Parameter(Mandatory=$true, HelpMessage = 'CMAKE_GENERATOR_PLATFORM')] +[String]$Platform, +[Parameter(Mandatory=$true, HelpMessage = 'CMAKE_GENERATOR_TOOLSET')] +[ValidateScript({ $_ -match 'host=(?[^,]*)'})] +[String]$Toolset +) + # keep all variables $old = ls env: # load development environment @@ -6,7 +31,12 @@ $old = ls env: $pwshmodule = Join-Path $info.instances.instance.installationPath ` "Common7\Tools\Microsoft.VisualStudio.DevShell.dll" | gi Import-Module $pwshmodule -Enter-VsDevShell -VsInstanceId $info.instances.instance.instanceId | Out-Null + +$Toolset -match 'host=(?[^,]*)' | Out-Null +$toolsetplatform = $Matches.arch + +Enter-VsDevShell -VsInstanceId $info.instances.instance.instanceId ` + -DevCmdArguments "/arch=$Platform /host_arch=$toolsetplatform" | Out-Null # keep new variables $new = ls env: # compare old and new environment From f5989aae9429229d7ff29e54044504e3a64a90b4 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Sat, 14 Jan 2023 18:42:34 +0100 Subject: [PATCH 22/49] Refs 16497. Module ownership refactor from Parser to Context. Signed-off-by: Miguel Barro --- include/xtypes/idl/Module.hpp | 1 + include/xtypes/idl/parser.hpp | 57 ++++++++++++++----------- test/unitary/generator/dependencies.cpp | 6 +-- test/unitary/parser/parser_test.cpp | 5 ++- test/unitary/parser/roundtrip.cpp | 3 -- 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/include/xtypes/idl/Module.hpp b/include/xtypes/idl/Module.hpp index bdb3778f..24bfc712 100644 --- a/include/xtypes/idl/Module.hpp +++ b/include/xtypes/idl/Module.hpp @@ -40,6 +40,7 @@ class DependencyModule; } class Module + : public std::enable_shared_from_this { protected: diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index ca2bf987..aa46069d 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -442,6 +442,8 @@ class Context CharType char_translation = CHAR; WideCharType wchar_type = WCHAR_T; + static const Context DEFAULT_CONTEXT; + // Results bool success = false; @@ -449,10 +451,12 @@ class Context bool scope = false) { std::map result; - if (module_ != nullptr) + + if(module_) { module_->fill_all_types(result, scope); } + return result; } @@ -461,11 +465,17 @@ class Context return get_all_types(true); } - Module& module() + idl::Module& module() { + if(!module_) + { + module_ = std::make_shared(); + } return *module_; } + inline void clear_context(); + ~Context() { clear_context(); @@ -475,12 +485,10 @@ class Context friend class Parser; std::shared_ptr instance_; - Module* module_ = nullptr; - inline void clear_context(); - + std::shared_ptr module_; }; -static const Context DEFAULT_CONTEXT = Context(); +inline const Context Context::DEFAULT_CONTEXT; class Parser : public std::enable_shared_from_this @@ -522,7 +530,7 @@ class Parser Context parse( const std::string& idl_string) { - Context context = DEFAULT_CONTEXT; + Context context = Context::DEFAULT_CONTEXT; parse(idl_string, context); return context; } @@ -533,12 +541,11 @@ class Parser { context.instance_ = shared_from_this(); context_ = &context; - context.module_ = &root_scope_; std::shared_ptr ast; if (!parser_.parse(idl_string.c_str(), ast)) { - context.success = false; + context_->success = false; context_->log(log::LogLevel::xDEBUG, "RESULT", "The parser found errors while parsing."); return false; @@ -546,7 +553,7 @@ class Parser ast = parser_.optimize_ast(ast); build_on_ast(ast); - context.success = true; + context_->success = true; context_->log(log::LogLevel::xDEBUG, "RESULT", "The parser finished."); return true; @@ -555,7 +562,7 @@ class Parser Context parse_file( const std::string& idl_file) { - Context context = DEFAULT_CONTEXT; + Context context = Context::DEFAULT_CONTEXT; parse_file(idl_file, context); return context; } @@ -563,7 +570,7 @@ class Parser Context parse_string( const std::string& idl_string) { - Context context = DEFAULT_CONTEXT; + Context context = Context::DEFAULT_CONTEXT; parse_string(idl_string, context); return context; } @@ -575,9 +582,9 @@ class Parser context.instance_ = shared_from_this(); context_ = &context; std::shared_ptr ast; - if (context.preprocess) + if (context_->preprocess) { - std::string file_content = context.preprocess_file(idl_file); + std::string file_content = context_->preprocess_file(idl_file); return parse(file_content, context); } @@ -605,7 +612,10 @@ class Parser void get_all_types( std::map& types_map) { - root_scope_.fill_all_types(types_map); + if(context_) + { + context_->module().fill_all_types(types_map); + } } class exception : public std::runtime_error @@ -645,7 +655,7 @@ class Parser const std::string& idl_file, const std::vector& includes) { - Context ctx = DEFAULT_CONTEXT; + Context ctx = Context::DEFAULT_CONTEXT; ctx.include_paths = includes; return ctx.preprocess_file(idl_file); } @@ -657,7 +667,6 @@ class Parser peg::parser parser_; Context* context_; - Module root_scope_; static std::shared_ptr instance_; static std::mutex mtx_; @@ -676,10 +685,12 @@ class Parser std::shared_ptr scope = nullptr) { using namespace peg::udl; + if (scope == nullptr) { - scope = std::shared_ptr(&root_scope_,[](Module*){}); + scope = context_->module().shared_from_this(); } + switch (ast->tag){ case "ANNOTATION_APPL"_: // Not supported yet @@ -2175,14 +2186,8 @@ void Context::clear_context() { if (clear) { - if (Parser::instance(false) == instance_) - { - Parser::destroy(); - } - else - { - instance_.reset(); - } + instance_.reset(); + module_.reset(); } } diff --git a/test/unitary/generator/dependencies.cpp b/test/unitary/generator/dependencies.cpp index 7da76cca..1043afab 100644 --- a/test/unitary/generator/dependencies.cpp +++ b/test/unitary/generator/dependencies.cpp @@ -126,7 +126,8 @@ void generation_roundtrip_test( << "===========================================" << std::endl; Parse again and check if it went as expected */ - idl::Context context = idl::parse(gen_idl); + idl::Context context; + idl::parse(gen_idl, context); ASSERT_TRUE(context.success); idl::Module& root_gen = context.module(); @@ -390,9 +391,8 @@ TEST (IDLGenerator, ambiguity) generation_ambiguity_resolution_check(root); std::string gen_idl = idl::generate(root); - // Debug - // std::cout << gen_idl << std::endl; + // parse anew idl::Context gen_context = idl::parse(gen_idl); ASSERT_TRUE(gen_context.success); generation_ambiguity_resolution_check(gen_context.module()); diff --git a/test/unitary/parser/parser_test.cpp b/test/unitary/parser/parser_test.cpp index 787080b8..724e0c1e 100644 --- a/test/unitary/parser/parser_test.cpp +++ b/test/unitary/parser/parser_test.cpp @@ -364,11 +364,12 @@ TEST (IDLParser, name_collision) { // Test that the parser accepts a keyword prefixed by an underscore even ignoring case, and // the resulting identifier doesn't have the prefixed underscore. - Context context = parse(R"( + Context context; + parse(R"( struct MyStruct { string _struct; - };)"); + };)", context); std::map result = context.module().get_all_types(); EXPECT_EQ(1, result.size()); diff --git a/test/unitary/parser/roundtrip.cpp b/test/unitary/parser/roundtrip.cpp index 5da18866..a31b3f74 100644 --- a/test/unitary/parser/roundtrip.cpp +++ b/test/unitary/parser/roundtrip.cpp @@ -315,9 +315,6 @@ TEST (IDLGenerator, roundtrip) // Generate another IDL from the parsed root module. std::string gen_idl = generator::module(context.module()); - // Debug - // std::cout << gen_idl << std::endl; - // Parse the generated IDL and check again. Context result = parse(gen_idl); check_result(result.module()); From e0cf42fbde00bff097cc256b53cfffab874e65d8 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Sun, 15 Jan 2023 00:58:29 +0100 Subject: [PATCH 23/49] Refs 16497. Simplify temporary files management Signed-off-by: Miguel Barro --- include/xtypes/idl/parser.hpp | 88 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index aa46069d..f30bc640 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -31,6 +31,14 @@ #include #include + +#ifdef _MSC_VER +# include +#else +# include +# include +#endif //_MSC_VER + #include #include #include @@ -39,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -229,29 +236,6 @@ class PreprocessorContext { public: - PreprocessorContext() = default; - - PreprocessorContext(const PreprocessorContext& pc) - : preprocess(pc.preprocess) - , preprocessor_exec(pc.preprocessor_exec) - , error_redir(pc.error_redir) - , strategy(pc.strategy) - , include_flag(pc.include_flag) - , include_paths(pc.include_paths) - {} - - PreprocessorContext& operator=(const PreprocessorContext& pc) - { - preprocess = pc.preprocess; - preprocessor_exec = pc.preprocessor_exec; - error_redir = pc.error_redir; - strategy = pc.strategy; - include_flag = pc.include_flag; - include_paths = pc.include_paths; - - return *this; - } - // Preprocessors capability to use shared memory (pipes) or stick to file input enum class preprocess_strategy { @@ -265,7 +249,6 @@ class PreprocessorContext preprocess_strategy strategy = EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY; std::string include_flag = EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES; std::vector include_paths; - mutable std::random_device rd; std::string preprocess_file( const std::string& idl_file) const @@ -292,6 +275,37 @@ class PreprocessorContext template std::string preprocess_string(const std::string& idl_string) const; +#ifdef _MSC_VER + std::pair get_temporary_file() const + { + // Create temporary filename + char filename_buffer[L_tmpnam]; + auto res = std::tmpnam(filename_buffer); + xtypes_assert(res, "Unable to create a temporary file", true); + + std::filesystem::path tmp(filename_buffer); + std::ofstream tmp_file(tmp); + xtypes_assert(tmp_file, "Unable to create a temporary file", true); + + return std::make_pair(std::move(tmp_file), std::move(tmp)); + } +#else + std::pair get_temporary_file() const + { + // Create temporary filename + static const std::filesystem::path tmpdir = std::filesystem::temp_directory_path(); + std::string tmp = (tmpdir / "xtypes_XXXXXX").string(); + int fd = mkstemp(tmp.data()); + xtypes_assert(fd != -1, "Unable to create a temporary file", true); + + std::ofstream tmp_file(tmp, std::ios_base::trunc | std::ios_base::out); + close(fd); + xtypes_assert(tmp_file, "Unable to create a temporary file", true); + + return std::make_pair(std::move(tmp_file), std::move(tmp)); + } +#endif // _MSC_VER + void replace_all_string( std::string& str, const std::string& from, @@ -369,27 +383,11 @@ template<> inline std::string PreprocessorContext::preprocess_string( const std::string& idl_string) const { - // Create temporary filename - auto tmp = std::filesystem::temp_directory_path(); - tmp /= "xtypes_"; - - { // random name generator - std::ostringstream os; - std::uniform_int_distribution<> dist(65,90); - std::mt19937 gen(rd()); - - for (int n = 0; n < 16; ++n) - { - os << char(dist(gen)); - } + auto [os, tmp] = get_temporary_file(); - tmp += os.str(); - } - - { // Populate - std::ofstream os(tmp); - os << idl_string; - } + // Populate + os << idl_string; + os.close(); auto processed = preprocess_file(tmp.string()); From 14f32e48a1c1ea2cf63cce6805f686a37e784c9d Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Mon, 16 Jan 2023 08:30:36 +0100 Subject: [PATCH 24/49] Refs 16497. Add github source indexing to pdb files Signed-off-by: Miguel Barro --- CMakeLists.txt | 48 +++++-- test/add_source_listing.ps1 | 262 ++++++++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+), 13 deletions(-) create mode 100644 test/add_source_listing.ps1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 324ca56e..a78d236f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,19 +39,6 @@ file(DOWNLOAD ${PROJECT_BINARY_DIR}/thirdparty/cpp-peglib/peglib.h ) -# MSVC always returns __cplusplus = 199711 unles we use the flag /Zc:__cplusplus then it follows the GNU behavior -if(MSVC) - execute_process(COMMAND - powershell -Command "$binarydir = \"${PROJECT_BINARY_DIR}\";" [=[ - $header = gi "$binarydir/thirdparty/cpp-peglib/peglib.h"; - (Get-Content -Encoding UTF8 -Path $header | - % { $_ -replace '__cplusplus', '_MSVC_LANG' } ) | - Set-Content -Encoding UTF8 -Path $header - ]=] - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - ) -endif(MSVC) - target_include_directories(xtypes INTERFACE $ @@ -63,6 +50,18 @@ target_include_directories(xtypes target_compile_features(xtypes INTERFACE cxx_std_17 cxx_variadic_macros) if(MSVC) + + # MSVC always returns __cplusplus = 199711 unles we use the flag /Zc:__cplusplus then it follows the GNU behavior + execute_process(COMMAND + powershell -Command "$binarydir = \"${PROJECT_BINARY_DIR}\";" [=[ + $header = gi "$binarydir/thirdparty/cpp-peglib/peglib.h"; + (Get-Content -Encoding UTF8 -Path $header | + % { $_ -replace '__cplusplus', '_MSVC_LANG' } ) | + Set-Content -Encoding UTF8 -Path $header + ]=] + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) + # Preprocessor: # target_compile_features() only enforces standard values like cxx_std_17. All other values like # cxx_variadic_macros are not enforced using flags but only will generate an error if not available. @@ -70,6 +69,12 @@ if(MSVC) # Encoding: # The header uses non-basic character set characters in narrow strings. Execution charset is hinted to allow UTF-8 target_compile_options(xtypes INTERFACE /Zc:preprocessor /execution-charset:UTF-8) + + # Check if source indexing tools are available + find_program(PDBSTR_PATH pdbstr + PATHS "[HKLM/SOFTWARE/Microsoft/Windows Kits/Installed Roots;KitsRoot10]" ENV WindowsSdkDir + PATH_SUFFIXES srcsrv "Debuggers/x64/srcsrv") + endif(MSVC) ##################################################################################### @@ -147,6 +152,23 @@ macro(compile_example) PRIVATE $<$:-Wall -Wextra -Wno-sign-compare -Wno-multichar> ) + + if(PDBSTR_PATH) + # get the tools path + get_filename_component(PDB_TOOLS_PATH "${PDBSTR_PATH}" DIRECTORY ABSOLUTE) + # add post build event + add_custom_command( + TARGET ${EXAMPLE_NAME} POST_BUILD + COMMENT "Adding source indexing to pdb symbols" + COMMAND "$,powershell,exit>" + -ExecutionPolicy Bypass + -File "${CMAKE_SOURCE_DIR}/test/add_source_listing.ps1" + -pdbfiles "$" + -toolsPath "${PDB_TOOLS_PATH}" + VERBATIM + ) + endif() + endmacro() if(XTYPES_BUILD_EXAMPLES) diff --git a/test/add_source_listing.ps1 b/test/add_source_listing.ps1 new file mode 100644 index 00000000..c29aac20 --- /dev/null +++ b/test/add_source_listing.ps1 @@ -0,0 +1,262 @@ +# 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 add_source_listing.ps1 +# + +Param( +[Parameter(Mandatory=$true, +ParameterSetName='shell', +HelpMessage = 'Pdb files to update with source indexing')] +[ValidateScript({Test-Path $_ -PathType Leaf})] +[String[]]$pdbs, +[Parameter(Mandatory=$true, +ParameterSetName='cli', +Position=0, +HelpMessage = 'Pdb files to update with source indexing as single string using ; as separator. Convenient to call the +script from cmd.')] +[ValidateScript({ $_ -split(";") | % { Test-Path $_ -PathType Leaf }})] +[String]$pdbfiles, +[Parameter( +HelpMessage = 'Path to the srcsrv ancillary tools')] +[ValidateScript({(Test-Path $_ -PathType Container) -and (ls -Path (Join-Path $_ *) -Include pdbstr.exe, srctool.exe) })] +[String]$toolsPath +) + +$ErrorActionPreference = 'Stop' + +# Turn cli string into array +if($pdbfiles) +{ + $pdbs = $pdbfiles.split(";") +} + +if($toolsPath) +{ + $pdbstr = (ls -path $toolsPath -Filter pdbstr.exe).fullname + $srctool = (ls -path $toolsPath -Filter srctool.exe).fullname +} +else +{ + # if not provided make some introspection + $kitskey = gi "HKLM:SOFTWARE/Microsoft/Windows Kits/Installed Roots" + $kitspath = $kitskey.GetValue($kitskey.GetValueNames() -match "KitsRoot") + $pdbstr = Resolve-Path "$kitspath/*/x64/srcsrv/pdbstr.exe" + $srctool = Resolve-Path "$kitspath/*/x64/srcsrv/srctool.exe" +} + +$ErrorActionPreference = 'SilentlyContinue' + +class ExcludePaths { + [string[]]$dirs + + [bool] Exclude([string]$file) { + # Change \ to / (avoid regex escaping issues) + return [bool]$this.dirs.Count -and + [bool]($file.replace("\","/") | sls -Pattern $this.dirs) + } + + [void] Add([string]$file) { + # Precondition: the file is not excluded + # 1. Get the folder + $dir = ($file | Split-Path).replace("\","/") + # 2. Remove those entries that are subfolders of the new one + if($this.dirs) + { + $this.dirs = ($this.dirs | sls -Pattern $dir -NotMatch).Line + } + # 3. Add the new one + $this.dirs += @($dir.replace("(","\(").replace(")","\)")) + } +} + +$excludes = New-Object -TypeName ExcludePaths + +class Repositories { + # Each individual repo keys: + # - name + # - commit + # - path + # - submodules array + [PSCustomObject[]]$repos + + [PSCustomObject] GetRepo([string]$file){ + return $this.GetRepo($file, $this.repos) + } + + [bool] AddRepo([string]$file){ + $new = [PSCustomObject]@{ + name = "" + commit = "" + path = "" + submodules = @() + } + $res = $this.AddRepo($file, $new) + if($res) + { + $this.repos += $new + } + return $res + } + + # Recursive implementation methods + + [PSCustomObject] GetRepo([string]$file, [PSCustomObject[]]$col){ + # ignore if empty + if($col.Count -eq 0) { return $null} + # Search for a repo whose path matches the file + $file = $file.replace("\","/") + $repo = $col.Where({$file -match $_.path},'SkipUntil',1) + # Check if the $file belong to some submodule + $subrepo = $Null + if($repo.submodules) { + $subrepo = $this.GetRepo($file, $repo.submodules) + } + # return $subrepo ?? $repo + if($subrepo) { + return $subrepo + } else { + return $repo + } + } + + [bool] AddRepo([string]$file, [PSCustomObject]$new){ + # Precondition the $file is not associated with a known repo + + # get associated idr + $dir = $file + if(Test-Path $file -PathType Leaf) { + $dir = ($file | Split-Path) + } + $dir.replace("\","/") + + $new.commit = git -C $dir log -n1 --pretty=format:'%h' 2>$null + if($new.commit -eq $null) { return $false } + # Find out the repo + $branches = git -C $dir branch -r --contains $new.commit + # get associated repos + $candidates = $branches | sls '^\s*(?\w+)/' | select -ExpandProperty Matches | + select -ExpandProperty Groups | ? name -eq 'remote' | sort | unique | + select -ExpandProperty Value + # filter out repo list + $new.name = ((git -C $dir remote -v | + sls "^(?\w+)\s+https://github.com/(?\S+).git").Matches | + % { [PSCustomObject]@{ repo = [String]$_.Groups['repo']; remote = [String]$_.Groups['remote']}} | + ? remote -in $candidates | Select -First 1).repo + + # get the path + $new.path = git -C $dir rev-parse --show-toplevel + + # populate submodules + $matches = (git -C $dir submodule | sls "^\s*\w+ (?[\S]+)").Matches + if($matches) + { + $new.submodules = $matches | % { + $subdir = "{0}/{1}" -f $new.path, $_.Groups['relpath'] + $subnew = [PSCustomObject]@{ + name = "" + commit = "" + path = "" + submodules = @() + } + if($this.AddRepo($subdir, $subnew)) { $subnew } + } + } + + return $true; + } +} + +$repos = New-Object -TypeName Repositories + +# Script to process the files into entries +$process = { + + $entry = @{} + # keep the file as id + $entry.id = $_ + + # Check if the file should be excluded + if($excludes.Exclude($_)) + { + return + } + + # Check the commit + $repo = $repos.GetRepo($_) + + # If there is no repo try to find one + if(!$repo) + { + if($repos.AddRepo($_)) + { + # retrieve the repo + $repo = $repos.GetRepo($_) + } + else + { + # If there is no repo ignore and update exclude + $excludes.Add($_) + return + } + } + + $entry.commit = $repo.commit + $entry.repo = $repo.name + $entry.repo_path = $repo.path + + # propagate + $entry = [PSCustomObject]$entry + Write-Output $entry +} + +foreach ($pdbfile in $pdbs) +{ + # Extract files and generate entries + $entries = & $srctool -r $pdbfile | Select -SkipLast 1 | % $process + + # keep the relative path + $groups = ($entries | ? repo -ne $null) | Group-Object -Property repo + $groups | % { + # calculate the relative path for all files + pushd $_.Group[0].repo_path + $_.Group | % { + $rp = (Resolve-Path -Path $_.id -Relative).replace(".\","").replace("\","/") + Add-Member -InputObject $_ -MemberType NoteProperty ` + -Name relpath -Value $rp } + popd + } + + # Generate the stream +$header = @' +SRCSRV: ini ------------------------------------------------ +VERSION=2 +VERCTRL=eProsima-Github +DATETIME={0} +SRCSRV: variables ------------------------------------------ +SRCSRVTRG=https://raw.githubusercontent.com/%var2%/%var3%/%var4% +SRCSRV: source files --------------------------------------- +'@ -f (Get-Date -Format "ddd, dd MMMM yyyy") + + $header = $header -split "`r?`n" + + $footer = 'SRCSRV: end ------------------------------------------------' + + # $tmp = New-TemporaryFile + $tmp = Join-Path $Env:TMP (Get-Random) + $entries | % { $header } {"{0}*{1}*{2}*{3}" -f $_.id, $_.repo, $_.commit, $_.relpath } { $footer } | Out-File $tmp -Encoding OEM + + # incorporate the stream into the file + & $pdbstr -w "-p:$pdbfile" -s:srcsrv "-i:$tmp" +} From 6c51e53814e75f830cfea30b6c94a62d14089d69 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Mon, 16 Jan 2023 10:33:08 +0100 Subject: [PATCH 25/49] Refs 16497. Enabling Windows Error Reporting for ci purposes Signed-off-by: Miguel Barro --- CMakeLists.txt | 28 +++++++- test/WER/CMakeLists.txt | 44 +++++++++++++ test/WER/wer.cpp | 139 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 test/WER/CMakeLists.txt create mode 100644 test/WER/wer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a78d236f..4d1c8e20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,22 @@ option(XTYPES_BUILD_EXAMPLES "Build examples." OFF) option(XTYPES_EXCEPTIONS "Enable xtypes exceptions in release (which are asserts in debug)." OFF) option(XTYPES_BUILD_TOOLS "Build tools." OFF) +include(CMakeDependentOption) + +cmake_dependent_option(ENABLE_WER + [=[Allow windows crash dump generation on crashes and timeouts. + WER can only be used if the binaries are launched for each individual + test otherwise some of the tests may not be executed. ]=] + OFF "WIN32" OFF) + +#[=[ + Timeout in seconds to raise a WER exception. + If combined with CTest timeout make sure CTest value is larger. +]=] +if(ENABLE_WER) + set(WER_TIMEOUT_TIME 10) +endif() + set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) @@ -197,10 +213,16 @@ macro(compile_test) target_link_libraries(${TEST_NAME} PRIVATE GTest::gtest + $ ) - gtest_discover_tests(${TEST_NAME} PROPERTIES ${TEST_PROPERTIES} ${MSVC_TEST_PROPERTIES}) + if(ENABLE_WER) + set(XTYPES_GTEST_FLAGS EXTRA_ARGS --gtest_catch_exceptions=0) + endif() + gtest_discover_tests(${TEST_NAME} + ${XTYPES_GTEST_FLAGS} + PROPERTIES ${TEST_PROPERTIES} ${MSVC_TEST_PROPERTIES}) endmacro() if(XTYPES_BUILD_TESTS) @@ -211,6 +233,10 @@ if(XTYPES_BUILD_TESTS) find_package(GTest CONFIG REQUIRED) include(GoogleTest) + if(ENABLE_WER) + add_subdirectory(test/WER) # first because the others may depend on it + endif() + if(MSVC) # Populate test environment if required diff --git a/test/WER/CMakeLists.txt b/test/WER/CMakeLists.txt new file mode 100644 index 00000000..11256eb6 --- /dev/null +++ b/test/WER/CMakeLists.txt @@ -0,0 +1,44 @@ +# 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_minimum_required(VERSION 3.16.3) +cmake_policy(VERSION 3.16.3...3.20.3) + +find_package(GTest CONFIG REQUIRED) + +# The purpose of this library is provide Windows Error Reporting support to the +# testing framework. In order to do so: +# +# - gtest must not catch all exceptions (C++/SEH like segmentation fault). +# This can be achieved modifying the flag testing::GTEST_FLAG(catch_exceptions) +# which is like using the ctest cli option --gtest_catch_exceptions=0. +# +# - CTest prevents OS error handling in tests child processes. This can be +# workaround by calling the windows API SetErrorMode(0) +# +# - CTest timeout mechanism uses windows API TerminateProcess() to wipe out a +# test tree. Thus it cannot be relied on. The OS has no chance of using WER. +# Instead a watchdog thread can be used to launch a termination exception that +# activates WER. + +add_library(wer INTERFACE) + +# introduce an alias to make even external and internal linking +add_library(eprosima::wer ALIAS wer) + +# Include this source on the project +target_sources(wer INTERFACE wer.cpp) + +# Specify the timeout time in seconds +target_compile_definitions(wer INTERFACE WER_ENABLED WER_TIMEOUT_TIME=${WER_TIMEOUT_TIME}) diff --git a/test/WER/wer.cpp b/test/WER/wer.cpp new file mode 100644 index 00000000..3839bf7b --- /dev/null +++ b/test/WER/wer.cpp @@ -0,0 +1,139 @@ +// 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. +// +// Note: In order to worked with GTEST the following environment variable must +// be set at runtime: set GTEST_CATCH_EXCEPTIONS=0 +// or the corresponding cli flag used --gtest_catch_exceptions=0 + +/** + * @file wer.hpp + * + */ + +#pragma once + +static_assert(_MSC_VER, "This header only applies for microsoft visual Studio compiler"); +static_assert(WER_TIMEOUT_TIME > 1, "The timeout in seconds must be defined"); + +#include +#include +#include +#include +#include +#include + +#define WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +# define NOMINMAX +#endif // NOMINMAX +#include + +// If the test is not using gtest ignore it +#if defined(__has_include) && __has_include() +# include +#endif + +namespace eprosima { + +class WerEnforcer +{ + std::thread watchdog_; + std::mutex mtx_; + std::condition_variable cond_; + bool done = false; + +public: + + WerEnforcer() + { + // Check environment to see if gtest is properly set up +# ifdef GOOGLETEST_INCLUDE_GTEST_GTEST_H_ + if (testing::GTEST_FLAG(catch_exceptions) == true) + { + const TCHAR* catch_exc = TEXT("GTEST_CATCH_EXCEPTIONS"); + TCHAR buffer[2]; + DWORD res = GetEnvironmentVariable(catch_exc, buffer, 2); + if( !res || buffer[0] != '0') + { + std::cerr << "The environment variable GTEST_CATCH_EXCEPTIONS must " + << "be 0 in order to activate WER. Otherwise use the gtest " + << "cli --gtest_catch_exceptions=0." << std::endl; + } + } +# endif + + // avoid CTest preemption of crashes + SetErrorMode(0); + SetUnhandledExceptionFilter(&WerEnforcer::UnhandledExceptionFilter); + + // launch watchdog timer + watchdog_ = std::thread([this] + { + std::unique_lock lock(mtx_); + + // Wait for test completion or timeout + cond_.wait_for( + lock, + std::chrono::seconds(WER_TIMEOUT_TIME), + [this] + { + return done; + }); + + // on timeout force crash for WER sake + if (!done) + { + std::cerr << "Raising WER fail fast exception for timeout" << std::endl; + RaiseFailFastException(nullptr, nullptr, 0); + } + }); + } + + ~WerEnforcer() + { + // no timeout, close watchdog thread + { + std::unique_lock lock(mtx_); + done = true; + } + + cond_.notify_one(); + watchdog_.join(); + } + + // Play along CTest JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION setting + static LONG UnhandledExceptionFilter( + _EXCEPTION_POINTERS* ExceptionInfo) + { + PEXCEPTION_RECORD ExceptionRecord = nullptr; + PCONTEXT ContextRecord = nullptr; + + if (ExceptionInfo) + { + ExceptionRecord = ExceptionInfo->ExceptionRecord; + ContextRecord = ExceptionInfo->ContextRecord; + } + std::cerr << "Raising WER fail fast exception for exception: " << + ExceptionRecord->ExceptionCode << std::endl; + RaiseFailFastException(ExceptionRecord, ContextRecord, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS); + + // unreachable + return -1; + } + +}; + +} // namespace eprosima + +const eprosima::WerEnforcer wer_singleton; From 0132181996e447dea09b9aae4a930b9e751f503f Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Mon, 16 Jan 2023 11:59:28 +0100 Subject: [PATCH 26/49] Refs 16497. Fix the examples Signed-off-by: Miguel Barro --- examples/complex_type.cpp | 2 +- examples/iterators.cpp | 4 ++-- test/unitary/parser/parser_test.cpp | 6 +----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/complex_type.cpp b/examples/complex_type.cpp index 56020c1c..eb14b6fc 100644 --- a/examples/complex_type.cpp +++ b/examples/complex_type.cpp @@ -101,7 +101,7 @@ int main() submod_b.enum_32(std::move(my_enum)); root.create_constant("MyConstEnum", enum_data); DynamicData my_const(primitive_type()); - my_const = 555ul; + my_const = UINT64_C(555); root.create_constant("MyConst", my_const); root.add_alias(abool); std::cout << idl::generate(root) << std::endl; diff --git a/examples/iterators.cpp b/examples/iterators.cpp index f40abbb3..25689d18 100644 --- a/examples/iterators.cpp +++ b/examples/iterators.cpp @@ -134,8 +134,8 @@ int main() my_data["my_double"] = -23.44; //ReadableDynamicDataRef::MemberIterator it = my_data.citems().begin(); - auto it = my_data.citems().begin(); - auto wit = my_data.items().begin(); + [[maybe_unused]] auto it = my_data.citems().begin(); + [[maybe_unused]] auto wit = my_data.items().begin(); for (auto&& elem : my_data.items()) // Loop through each `ReadableDynamicDataRef`. { diff --git a/test/unitary/parser/parser_test.cpp b/test/unitary/parser/parser_test.cpp index 724e0c1e..e5e02570 100644 --- a/test/unitary/parser/parser_test.cpp +++ b/test/unitary/parser/parser_test.cpp @@ -1324,11 +1324,7 @@ TEST (IDLParser, union_tests) EXPECT_EQ(data["union_c"].d().value(), 2); data["union_c"].d(3); EXPECT_EQ(data["union_c"].d().value(), 3); -#ifdef _MSC_VER - data["union_c"]["my_uint64"] = 314ull; -#else - data["union_c"]["my_uint64"] = 314ul; -#endif // _MSC_VER + data["union_c"]["my_uint64"] = UINT64_C(314); EXPECT_EQ(data["union_c"].d().value(), 1); data["union_c"]["my_int32"] = 314; EXPECT_EQ(data["union_c"].d().value(), 0); From 81c70f8bae98d26f973978ff9ca9407196b236d1 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Mon, 16 Jan 2023 12:15:22 +0100 Subject: [PATCH 27/49] Refs 16497. Fixing old ci Signed-off-by: Miguel Barro --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24d4ced2..4b4bca36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,15 +10,15 @@ on: jobs: xtypes_CI: - runs-on: ubuntu-20.04 - container: ubuntu:focal + runs-on: ubuntu-latest + container: ubuntu:jammy steps: - name: Download required dependencies run: | apt update - DEBIAN_FRONTEND=noninteractive apt install -y cmake gcc g++ git valgrind + DEBIAN_FRONTEND=noninteractive apt install -y cmake gcc g++ git valgrind libgtest-dev - uses: actions/checkout@v2 with: From 1696ece811c05eb243d1f7e70d40f0f18cd652e7 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Wed, 18 Jan 2023 21:35:16 +0100 Subject: [PATCH 28/49] Refs 16497. avoid deprecated string conversions Signed-off-by: Miguel Barro --- include/xtypes/DynamicDataImpl.hpp | 24 +--- include/xtypes/StringConversion.hpp | 148 ++++++++++++++++++++++ include/xtypes/UnionType.hpp | 20 +-- include/xtypes/idl/parser.hpp | 42 ++---- test/unitary/xtypes/string_conversion.cpp | 107 ++++++++++++++++ test/unitary/xtypes/union_type.cpp | 1 + 6 files changed, 275 insertions(+), 67 deletions(-) create mode 100644 include/xtypes/StringConversion.hpp create mode 100644 test/unitary/xtypes/string_conversion.cpp diff --git a/include/xtypes/DynamicDataImpl.hpp b/include/xtypes/DynamicDataImpl.hpp index 4659a5cc..02edb0f1 100644 --- a/include/xtypes/DynamicDataImpl.hpp +++ b/include/xtypes/DynamicDataImpl.hpp @@ -18,10 +18,9 @@ #define EPROSIMA_XTYPES_DYNAMIC_DATA_IMPL_HPP_ #include +#include #include -#include -#include namespace eprosima { namespace xtypes { @@ -188,26 +187,13 @@ inline std::string ReadableDynamicDataRef::to_string() const ss << "<" << type_name << "> " << node.data().value(); break; case TypeKind::WSTRING_TYPE: - { - std::wstring_convert, wchar_t> converter; - ss << "<" << type_name << "> " << converter.to_bytes(node.data().value()); + ss << "<" << type_name << "> "; + ss << code_conversion_tool(node.data().value()); break; - } case TypeKind::STRING16_TYPE: - { - std::string str = ""; - char cstr[3] = "\0"; - mbstate_t mbs; - for (const auto& it : node.data().value()) - { - std::memset(&mbs, 0, sizeof(mbs)); - std::memmove(cstr, "\0\0\0", 3); - std::c16rtomb(cstr, it, &mbs); - str.append(std::string(cstr)); - } - ss << "<" << type_name << "> " << str; + ss << "<" << type_name << "> "; + ss << code_conversion_tool(node.data().value()); break; - } case TypeKind::ARRAY_TYPE: ss << "<" << type_name << ">"; break; diff --git a/include/xtypes/StringConversion.hpp b/include/xtypes/StringConversion.hpp new file mode 100644 index 00000000..d50da038 --- /dev/null +++ b/include/xtypes/StringConversion.hpp @@ -0,0 +1,148 @@ +/* + * Copyright 2023, 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. + * +*/ + +#ifndef EPROSIMA_STRING_CONVERSION_HPP_ +#define EPROSIMA_STRING_CONVERSION_HPP_ + +#include + +namespace eprosima { + +// The purpose of this classes is workaround C++17 deprecation of STL string conversion APIs +namespace detail { + +template +struct choose_codecvt; + +template +struct choose_codecvt_base +{ + using cvt = std::codecvt; +}; + +template +struct choose_codecvt + : choose_codecvt_base +{ + template + static std::codecvt_base::result translate(const facet& f, + std::mbstate_t& state, + const char* from, + const char* from_end, + const char*& from_next, + wchar* to, + wchar* to_end, + wchar*& to_next) + { + return f.in(state, from, from_end, from_next, to, to_end, to_next); + } +}; + +template +struct choose_codecvt + : choose_codecvt_base +{ + template + static std::codecvt_base::result translate(const facet& f, + std::mbstate_t& state, + const wchar* from, + const wchar* from_end, + const wchar*& from_next, + char* to, + char* to_end, + char*& to_next) + { + return f.out(state, from, from_end, from_next, to, to_end, to_next); + } +}; + +} // detail + +template +std::basic_string code_conversion_tool(const std::basic_string_view& input) +{ + using namespace std; + using namespace detail; + using choose = choose_codecvt; + + locale loc; + // on mac STL ALL codecvt partial specializations use char as external type + auto& conv_facet = use_facet(loc); + + const unsigned int buffer_size = 64; + out buffer[buffer_size]; + + mbstate_t mb{}; + out* to_next; + std::basic_string output; + const in* from_next = input.data(); + const in* from_end = from_next + input.size(); + bool processing = true; + + // iterate if buffer gets filled + while (processing) + { + codecvt_base::result res = choose::translate( + conv_facet, + mb, + from_next, + from_end, + from_next, + buffer, + buffer + buffer_size, + to_next); + + switch (res) + { + case codecvt_base::ok: + // gcc implementation mixes up ok and partial + if(from_next == from_end) + { + // we are done + processing = false; + // append the contents remember + output.append(buffer, to_next - buffer); + break; + } + [[fallthrough]]; + case codecvt_base::partial: + // insert current buffer content + output.append(buffer, buffer_size); + break; + + case codecvt_base::error: + throw std::range_error("encountered a character that could not be converted"); + + case codecvt_base::noconv: + break; + // case codecvt_base::noconv doesn't apply in this overload but not including it arises a warning + } + } + + return output; +} + +template +std::basic_string code_conversion_tool(const std::basic_string& input) +{ + return code_conversion_tool(std::basic_string_view{input}); +} + +} // eprosima + +#endif // EPROSIMA_STRING_CONVERSION_HPP_ + diff --git a/include/xtypes/UnionType.hpp b/include/xtypes/UnionType.hpp index 1f051515..9d385ae4 100644 --- a/include/xtypes/UnionType.hpp +++ b/include/xtypes/UnionType.hpp @@ -21,14 +21,13 @@ #include #include #include +#include #include #include #include #include -#include #include -#include #include namespace eprosima { @@ -1067,18 +1066,7 @@ class UnionType : public AggregationType break; case TypeKind::CHAR_16_TYPE: { - std::u16string wstr = u""; - char16_t c16str[3] = u"\0"; - mbstate_t mbs; - - for (const auto& it : label) - { - std::memset(&mbs, 0, sizeof(mbs)); - std::memmove(c16str, u"\0\0\0", 3); - std::mbrtoc16(c16str, &it, 3, &mbs); - wstr.append(std::u16string(c16str)); - } - + std::u16string wstr = code_conversion_tool(label); char16_t value; // Check if comes with "'" if (label.size() == 1) @@ -1094,10 +1082,8 @@ class UnionType : public AggregationType break; case TypeKind::WIDE_CHAR_TYPE: { - using convert_type = std::codecvt_utf8; - std::wstring_convert converter; - std::wstring temp = converter.from_bytes(label); wchar_t value; + std::wstring temp = code_conversion_tool(label); // Check if comes with "'" if (label.size() == 1) { diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index f30bc640..360d1afd 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -23,10 +23,11 @@ #include #include +#include +#include +#include #include #include -#include -#include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -1029,16 +1029,8 @@ class Parser { context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_CHAR"), ast); } - std::u16string temp = u""; - char16_t c16str[3] = u"\0"; - mbstate_t mbs; - for (const auto& it : literal) - { - std::memset(&mbs, 0, sizeof(mbs)); - std::memmove(c16str, u"\0\0\0", 3); - std::mbrtoc16(c16str, &it, 3, &mbs); - temp.append(std::u16string(c16str)); - } + + std::u16string temp = code_conversion_tool(literal); data = temp[0]; break; } @@ -1048,11 +1040,9 @@ class Parser { context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_CHAR"), ast); } - using convert_type = std::codecvt_utf8; - std::wstring_convert converter; - std::wstring temp = converter.from_bytes(std::string(literal.data(), literal.size())); - wchar_t value = temp[0]; - data = value; + + std::wstring temp = code_conversion_tool(literal); + data = temp[0]; break; } case TypeKind::STRING_TYPE: @@ -1085,24 +1075,14 @@ class Parser { context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_STRING"), ast); } - using convert_type = std::codecvt_utf8; - std::wstring_convert converter; - std::wstring value = converter.from_bytes(aux); + + std::wstring value = code_conversion_tool(aux); data = value; break; } case TypeKind::STRING16_TYPE: { - std::u16string temp = u""; - char16_t c16str[3] = u"\0"; - mbstate_t mbs; - for (const auto& it : literal) - { - std::memset(&mbs, 0, sizeof(mbs)); - std::memmove(c16str, u"\0\0\0", 3); - std::mbrtoc16(c16str, &it, 3, &mbs); - temp.append(std::u16string(c16str)); - } + std::u16string temp = code_conversion_tool(literal); data = temp; break; } diff --git a/test/unitary/xtypes/string_conversion.cpp b/test/unitary/xtypes/string_conversion.cpp new file mode 100644 index 00000000..c3b735f8 --- /dev/null +++ b/test/unitary/xtypes/string_conversion.cpp @@ -0,0 +1,107 @@ +// Copyright 2023 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 + +using namespace std; +using namespace eprosima; + +TEST (StringConversion, from_char_to_wchar_short) +{ + string short_str{"test"}; + wstring expected{L"test"}; + ASSERT_EQ(code_conversion_tool(short_str), expected); +} + +TEST (StringConversion, from_char_to_wchar_long) +{ + string long_str{"test"}; + wstring expected{L"test"}; + + for(int i = 0; i < 1000; ++i) + { + int car = i % 74 + 48; + long_str.append({static_cast(car)}); + expected.append({static_cast(car)}); + } + + ASSERT_EQ(code_conversion_tool(long_str), expected); +} + +TEST (StringConversion, from_wchar_to_char_short) +{ + wstring short_str{L"test"}; + string expected{"test"}; + ASSERT_EQ(code_conversion_tool(short_str), expected); +} + +TEST (StringConversion, from_wchar_to_char_long) +{ + wstring long_str{L"test"}; + string expected{"test"}; + + for(int i = 0; i < 1000; ++i) + { + int car = i % 74 + 48; + long_str.append({static_cast(car)}); + expected.append({static_cast(car)}); + } + + ASSERT_EQ(code_conversion_tool(long_str), expected); +} + +TEST (StringConversion, from_char_to_char16_short) +{ + string short_str{"test"}; + u16string expected{u"test"}; + ASSERT_EQ(code_conversion_tool(short_str), expected); +} + +TEST (StringConversion, from_char_to_char16_long) +{ + string long_str{"test"}; + u16string expected{u"test"}; + + for(int i = 0; i < 1000; ++i) + { + int car = i % 74 + 48; + long_str.append({static_cast(car)}); + expected.append({static_cast(car)}); + } + + ASSERT_EQ(code_conversion_tool(long_str), expected); +} + +TEST (StringConversion, from_char16_to_char_short) +{ + u16string short_str{u"test"}; + string expected{"test"}; + ASSERT_EQ(code_conversion_tool(short_str), expected); +} + +TEST (StringConversion, from_char16_to_char_long) +{ + u16string long_str{u"test"}; + string expected{"test"}; + + for(int i = 0; i < 1000; ++i) + { + int car = i % 74 + 48; + long_str.append({static_cast(car)}); + expected.append({static_cast(car)}); + } + + ASSERT_EQ(code_conversion_tool(long_str), expected); +} diff --git a/test/unitary/xtypes/union_type.cpp b/test/unitary/xtypes/union_type.cpp index 38bf43df..379f582f 100644 --- a/test/unitary/xtypes/union_type.cpp +++ b/test/unitary/xtypes/union_type.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include From 6fcb0c49f3b37601d214133b5fe28bc137503d67 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 17 Jan 2023 17:03:00 +0100 Subject: [PATCH 29/49] Refs 16497. New CI Signed-off-by: Miguel Barro --- .github/workflows/ci.yml | 54 ++-- .github/workflows/reusable-github-ci.yml | 379 +++++++++++++++++++++++ CMakeLists.txt | 9 +- test/add_source_listing.ps1 | 58 +++- 4 files changed, 462 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/reusable-github-ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b4bca36..7e1392fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,43 +1,31 @@ name: CI for eProsima xTypes on: + workflow_dispatch: push: branches: - - master + - 'master' + - 'main' + paths-ignore: + - '**.md' + - '**.txt' + - '!**/CMakeLists.txt' pull_request: branches: - - '**' + - 'master' + - 'main' + paths-ignore: + - '**.md' + - '**.txt' + - '!**/CMakeLists.txt' jobs: xtypes_CI: - runs-on: ubuntu-latest - container: ubuntu:jammy - - steps: - - - name: Download required dependencies - run: | - apt update - DEBIAN_FRONTEND=noninteractive apt install -y cmake gcc g++ git valgrind libgtest-dev - - - uses: actions/checkout@v2 - with: - path: src/xtypes - - - name: Build - working-directory: src/xtypes - run: | - ls -la - cmake . -DXTYPES_BUILD_TESTS=ON -DXTYPES_BUILD_EXAMPLES=ON -DXTYPES_EXCEPTIONS=ON -DCTEST_MEMORYCHECK_COMMAND=valgrind -DCTEST_MEMORYCHECK_COMMAND_OPTIONS='-q --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=50' - make -j${nproc} - - - name: Test - working-directory: src/xtypes - run: | - ctest -VV -D ExperimentalTest --no-compress-output - - - name: Valgrind - working-directory: src/xtypes - if: startsWith(github.head_ref, 'valgrind') - run: | - ctest -VV -D ExperimentalMemCheck --no-compress-output -LE NoMemoryCheck + uses: ./.github/workflows/reusable-github-ci.yml + if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-ci') }} + with: + label: "Running-CI" + os: "[\"ubuntu-latest\",\"windows-latest\",\"macos-latest\"]" + config: "[\"RelWithDebInfo\"]" + vs_toolset: "[\"v143\",\"v142\"]" + cmake_args: "[\"-DXTYPES_EXCEPTIONS=ON\",\"-DXTYPES_EXCEPTIONS=OFF\"]" diff --git a/.github/workflows/reusable-github-ci.yml b/.github/workflows/reusable-github-ci.yml new file mode 100644 index 00000000..705e3d86 --- /dev/null +++ b/.github/workflows/reusable-github-ci.yml @@ -0,0 +1,379 @@ +name: reusable Fast-DDS continuous integration + +on: + workflow_call: + inputs: + label: + description: 'id associated to the workflow. Must univocally identify artifacts.' + required: true + type: string + os: + description: 'A json array listing github hosts' + required: true + type: string + config: + description: 'A json array listing build configs' + required: true + type: string + vs_toolset: + description: 'A json array listing visual studio toolsets' + required: false + type: string + cmake_args: + description: 'A json array listing extra arguments for cmake cli' + required: false + type: string + ctest_args: + description: 'Extra arguments for ctest cli' + required: false + type: string + +defaults: + run: + shell: pwsh + +jobs: + + build-matrix: + runs-on: windows-latest + outputs: + configs-matrix: ${{ steps.set-matrix.outputs.configs-matrix }} + steps: + - id: set-matrix + run: | + # Use a vector of dictionaries instead of a fixed size matrix + $configs = @() + + foreach($cmake_args in (ConvertFrom-Json '${{ inputs.cmake_args }}')) + { + $map = @{} + $map.cmake_args = $cmake_args + + foreach($os in (ConvertFrom-Json '${{ inputs.os }}')) + { + $map.os = $os + + foreach($config in (ConvertFrom-Json '${{ inputs.config }}')) + { + $map.config = $config + + if( $os -match "windows" ) + { + foreach($ts in (ConvertFrom-Json '${{ inputs.vs_toolset }}')) + { + $map.toolset = $ts + $configs += $map.Clone() + } + } + else + { + $configs += $map.Clone() + } + } + } + } + + 'configs-matrix=' + (ConvertTo-Json $configs -Compress) | + Out-File $Env:GITHUB_OUTPUT -Append + + build-and-test-ci: + needs: build-matrix + strategy: + matrix: + configs: ${{ fromJSON(needs.build-matrix.outputs.configs-matrix) }} + fail-fast: false + name: > + ${{ matrix.configs.os }} ${{ matrix.configs.config }} + ${{ contains(matrix.configs.os, 'windows') && matrix.configs.toolset || '' }} ${{ matrix.configs.cmake_args }} + runs-on: ${{ matrix.configs.os }} + steps: + + - name: Setup environment + run: | + # Introduce EchoArgs to check cmake calls + $mdir = New-Item -Type Directory -Path (Join-Path ($Env:TMP ?? "/tmp") (New-GUID)) + if($IsWindows) + { + Save-Module -Name Pscx -Path $mdir -Repository PSGallery + $echo = gci -Path $mdir -R -Filter EchoArgs* + } + else # on unix redirect to echo + { + $mdir = New-Item -Type Directory -Path (Join-Path /tmp (New-GUID)) + $echo = New-Item -Type SymbolicLink -Target (which echo) -Path (Join-Path $mdir EchoArgs) + } + "PATH=$Env:PATH" + [IO.Path]::PathSeparator + ($echo | Split-Path | gi) + | Out-File $Env:GITHUB_ENV -Append -Encoding OEM + + # Handle single target/multi target + $env_variables = @() + $env_variables += 'EXTRA_CMAKE_ARGS=${{ matrix.configs.cmake_args }}' + + if($IsWindows) + { + $env_variables += + 'CXXFLAGS=/MP', + 'CONFIG_TYPE=--config ${{ matrix.configs.config }}', + 'BUILD_TYPE=-A x64 -T ${{ matrix.configs.toolset }},host=x64', + 'TEST_CONFIG=--build-config ${{ matrix.configs.config }}' + } + elseif($IsMacOS) + { + [int]$cpus = sysctl -n hw.ncpu + $env_variables += + 'BUILD_TYPE=-DCMAKE_BUILD_TYPE=${{ matrix.configs.config }}', + "NUMBER_OF_PROCESSORS=$cpus" + } + else + { + [int]$cpus = ((gc /proc/cpuinfo | + sls "cpu cores\s+:\s+(?\d+)").Matches.Groups | + ? name -eq thread | Measure-Object -Property value -Sum).sum + + $env_variables += + 'BUILD_TYPE=-DCMAKE_BUILD_TYPE=${{ matrix.configs.config }}', + "NUMBER_OF_PROCESSORS=$cpus" + } + + Write-Output $env_variables + $env_variables | Out-File $Env:GITHUB_ENV -Append -Encoding OEM + + - name: Enable WER on windows + id: WERSetup + if: ${{ contains(matrix.configs.os, 'windows') }} + run: | + $wer = "HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting" + $ld = Join-Path $wer LocalDumps + $key = Get-Item $wer + + if("Disabled" -in $key.Property) { + Set-ItemProperty -Path $wer -Name "Disabled" -Value 0 + } else { + New-ItemProperty -Path $wer -Name "Disabled" -Value 0 -PropertyType DWord + } + + if(Test-Path $ld) { $key = Get-Item $ld } else { $key = New-Item -Path $wer -Name "LocalDumps" } + + #destination folder + $crashdir = New-Item -Path "CrashDumps" -Type Directory + if("DumpFolder" -in $key.Property) { + Set-ItemProperty -Path $ld -Name "DumpFolder" -Value $crashdir + } else { + New-ItemProperty -Path $ld -Name "DumpFolder" -Value $crashdir -PropertyType ExpandString + } + "DumpFolder=$crashdir" | Out-File $Env:GITHUB_OUTPUT -Append + + # up to DumpCount files in the folder + if("DumpCount" -in $key.Property) { + Set-ItemProperty -Path $ld -Name "DumpCount" -Value 100 + } else { + New-ItemProperty -Path $ld -Name "DumpCount" -Value 100 -PropertyType DWord + } + + # 2 -> full dump + if("DumpType" -in $key.Property) { + Set-ItemProperty -Path $ld -Name "DumpType" -Value 2 + } else { + New-ItemProperty -Path $ld -Name "DumpType" -Value 2 -PropertyType DWord + } + + # WER service is manual by default + Start-Service WerSvc + + - name: Install googletest system wide + run: | + if($IsLinux) + { + sudo apt install -y libgtest-dev + exit + } + elseif($IsMacOS) + { + brew install googletest + exit + } + + # Windows requires installation + git clone --branch release-1.11.0 https://github.com/google/googletest.git + + # Show the args + EchoArgs -DBUILD_GMOCK=ON "$Env:BUILD_TYPE".split(" ") -Dgtest_force_shared_crt=ON -DCMAKE_VERBOSE_MAKEFILE=ON ` + -B ./build/googletest "$Env:BIN_ARCH".split(" ") "$Env:HOST_ARCH".split(" ") ./googletest + + # Generate + cmake -DBUILD_GMOCK=ON "$Env:BUILD_TYPE".split(" ") -Dgtest_force_shared_crt=ON -DCMAKE_VERBOSE_MAKEFILE=ON ` + -B ./build/googletest "$Env:BIN_ARCH".split(" ") "$Env:HOST_ARCH".split(" ") ./googletest + + # Build and install elevated if required + cmake --build ./build/googletest --target install "$Env:CONFIG_TYPE".split(" ") -j $Env:NUMBER_OF_PROCESSORS | + Tee-Object -FilePath gtest.log + + # Hint install dir + $pattern = "-- Installing:\s+(?.*)/GTestConfig.cmake" + $matches = sls -Path gtest.log -Pattern $pattern + $Env:GTest_DIR = ($matches.Matches.Groups | ? name -eq cmake_path).Value + ("GTest_DIR=" + $Env:GTest_DIR) | Out-File $Env:GITHUB_ENV -Append -Encoding OEM + + # clean up + 'build', 'googletest', 'gtest.log' | del -Recurse -Force + + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Build + id: build + run: | + # track pull requests to fix source indexing + if($IsWindows) + { + git config --local remote.origin.fetch '+refs/pull/*:refs/remotes/origin/pull/*' + git fetch origin 2>$null + } + + # Build + $cmakeargs = @() + $cmakeargs += "-DENABLE_PDB_INDEXING=ON" + $cmakeargs += "-DENABLE_WER=ON" + $cmakeargs += "-DXTYPES_BUILD_TESTS=ON" + $cmakeargs += "-DXTYPES_BUILD_EXAMPLES=ON" + $cmakeargs += $Env:EXTRA_CMAKE_ARGS + $cmakeargs += "$Env:BUILD_TYPE".split(" ") + + # Show the args + EchoArgs "-DCMAKE_INSTALL_PREFIX=$(Join-Path (pwd) install)" $cmakeargs -B build . + + "::group::cmake generation step" + cmake "-DCMAKE_INSTALL_PREFIX=$(Join-Path (pwd) install)" $cmakeargs -B build . + "::endgroup::" + + gci # TODO: remove this + + # Show the args + EchoArgs --build build "$Env:CONFIG_TYPE".split(" ") --target install -j $Env:NUMBER_OF_PROCESSORS + + "::group::cmake build step" + cmake --build build "$Env:CONFIG_TYPE".split(" ") --target install -j $Env:NUMBER_OF_PROCESSORS + "::endgroup::" + + - name: Test + if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') }} + id: test + run: | + $ErrorActionPreference = 'Continue' + # Create a junit file for test results + $junit = New-Item -Path ./junit.xml -ItemType File + 'JUNIT_LOG=' + $junit.FullName | Out-File $Env:GITHUB_ENV -Append -Encoding OEM + + # Show the arguments + EchoArgs --test-dir build "$Env:TEST_CONFIG".split(" ") --output-junit $junit -j $Env:NUMBER_OF_PROCESSORS + + # Run the testing + "::group::ctest summary" + ctest --test-dir build "$Env:TEST_CONFIG".split(" ") --output-junit $junit -j $Env:NUMBER_OF_PROCESSORS + "::endgroup::" + + # Avoid disturbing exit code 1 message + $LASTEXITCODE=0 + + - name: Test Summary + id: summary + if: ${{ steps.test.outcome == 'success' }} + run: | + $ErrorActionPreference = 'Continue' + $failed = 0 + + # If the CMake version (3.21 et seq.) supports junit use it + if((Test-Path $Env:JUNIT_LOG) -and (gi $Env:JUNIT_LOG).Length ) + { + # ancillary for markdown summary + $modules = Get-Module -ListAvailable | Select ModuleType, Version, Name + if(!($modules | ? Name -eq "MarkdownPS")) + { + Install-Module -Name MarkdownPS -Force + } + + [xml]$res = gc $Env:JUNIT_LOG + [long]$failed = $res.testsuite.failures + + # Summary + $res.testsuite | select name, tests, failures, disabled, hostname, time, timestamp | + New-MDTable | Tee-Object -FilePath $Env:GITHUB_STEP_SUMMARY -Append + + if($failed) + { + # list the failures if any + "::group::Failures Summary" + $failures = $res.testsuite.testcase | ? status -eq fail + $failures | select name, time | format-list + "::endgroup::" + + # list faulty tests output + "::group::Failed tests output" + $failures + "::endgroup::" + + # populate a log folder with the failures + $logFolder = New-Item -Type Directory -Path test_logs + pushd $logFolder + $failures | % { $_.'system-out' | Set-Content -Path ($_.name + ".txt") } + popd + + "TestLogFolder=" + $logFolder.FullName | Out-File $Env:GITHUB_OUTPUT -Append + } + + } + + if($IsWindows -and $failed) + { + # list crash dumps files ordered by date to hint how pid maps to test number + $dumpfolder = gi (gi "HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps").GetValue('DumpFolder') + + # upload binaries of faulty tests: + $test_bin = ((ls -Path $dumpfolder -Filter *.dmp).name | + sls "(?[^\(^\)^\.]+).*\.\d+\.dmp").Matches | + % { $_.Groups['file'].Value } | Get-Unique + $exes = gci -Path ./build/* -R -Include "*.pdb", "*.exe" + $exes | ? basename -in $test_bin | Move-Item -Destination $dumpfolder + + "::group::Crash dump files" + gci $dumpfolder | Sort-Object LastWriteTime + "::endgroup::" + } + + if($failed) + { + $msg = "$failed test(s) failed" + "TestErrors=" + $msg | Out-File $Env:GITHUB_OUTPUT -Append + Write-Error $msg; + } + + # Avoid disturbing exit code 1 message + $LASTEXITCODE=0 + + - name: Upload test errors + if: ${{ steps.summary.outputs.TestLogFolder != 0 }} + uses: actions/upload-artifact@v3 + with: + name: test-errors-${{ inputs.label }}-${{ matrix.configs.os }}${{ matrix.configs.toolset != 0 && '-' || ''}}${{ matrix.configs.toolset }}-${{ matrix.configs.config }} + path: ${{ steps.summary.outputs.TestLogFolder }} + + - name: Upload crash dumps + if: ${{ contains(matrix.configs.os, 'windows') && steps.summary.outputs.TestErrors != 0 }} + uses: actions/upload-artifact@v3 + with: + name: crash-dumps-${{ inputs.label }}-${{ matrix.configs.os }}-${{ matrix.configs.toolset }}-${{ matrix.configs.config }} + path: ${{ steps.WERSetup.outputs.DumpFolder }} + + - name: Check test failures + if: ${{ steps.summary.outputs.TestErrors != 0 }} + uses: actions/github-script@v6 + with: + script: | + const test_info = '${{ steps.summary.outputs.TestErrors }}'; + + // test errors + if (!!test_info) + { + core.setFailed(test_info); + } diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d1c8e20..c3d4a48f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,12 @@ option(XTYPES_BUILD_TOOLS "Build tools." OFF) include(CMakeDependentOption) +cmake_dependent_option(ENABLE_PDB_INDEXING + [=[Uses the PDBStr tool to modify the pdb (symbol files). + The new files will download the sources from github simplifying + post mortem debugging of failing tests dumps (WER). ]=] + OFF "MSVC" OFF) + cmake_dependent_option(ENABLE_WER [=[Allow windows crash dump generation on crashes and timeouts. WER can only be used if the binaries are launched for each individual @@ -169,7 +175,7 @@ macro(compile_example) $<$:-Wall -Wextra -Wno-sign-compare -Wno-multichar> ) - if(PDBSTR_PATH) + if(ENABLE_PDB_INDEXING AND PDBSTR_PATH) # get the tools path get_filename_component(PDB_TOOLS_PATH "${PDBSTR_PATH}" DIRECTORY ABSOLUTE) # add post build event @@ -181,6 +187,7 @@ macro(compile_example) -File "${CMAKE_SOURCE_DIR}/test/add_source_listing.ps1" -pdbfiles "$" -toolsPath "${PDB_TOOLS_PATH}" + # -Verbose VERBATIM ) endif() diff --git a/test/add_source_listing.ps1 b/test/add_source_listing.ps1 index c29aac20..67e9a9b0 100644 --- a/test/add_source_listing.ps1 +++ b/test/add_source_listing.ps1 @@ -14,6 +14,13 @@ # # @file add_source_listing.ps1 # +# Preconditions: +# In order for the algorithm to work with github pull request the associated repos +# must enable the tracking of the pull request references. This can be set globally in +# the CI as: +# git config --global remote.origin.fetch '+refs/pull/*:refs/remotes/origin/pull/*' +# Note actions/checkout preempts it and may be force locally in the repo as: +# git config --local remote.origin.fetch '+refs/pull/*:refs/remotes/origin/pull/*'; git fetch origin Param( [Parameter(Mandatory=$true, @@ -56,6 +63,8 @@ else $srctool = Resolve-Path "$kitspath/*/x64/srcsrv/srctool.exe" } +Write-Verbose "Framework tools: '$pdbstr' '$srctool'" + $ErrorActionPreference = 'SilentlyContinue' class ExcludePaths { @@ -142,18 +151,53 @@ class Repositories { $dir.replace("\","/") $new.commit = git -C $dir log -n1 --pretty=format:'%h' 2>$null + + if($new.commit) + { + Write-Verbose "Found new repo commit: git -C $dir log -n1 --pretty=format:'%h' => $($new.commit)" + } + if($new.commit -eq $null) { return $false } # Find out the repo $branches = git -C $dir branch -r --contains $new.commit + + if($branches) + { + Write-Verbose "Commit branches: git -C $dir branch -r --contains $($new.commit) => $branches" + } + # get associated repos $candidates = $branches | sls '^\s*(?\w+)/' | select -ExpandProperty Matches | select -ExpandProperty Groups | ? name -eq 'remote' | sort | unique | select -ExpandProperty Value + # filter out repo list - $new.name = ((git -C $dir remote -v | - sls "^(?\w+)\s+https://github.com/(?\S+).git").Matches | - % { [PSCustomObject]@{ repo = [String]$_.Groups['repo']; remote = [String]$_.Groups['remote']}} | - ? remote -in $candidates | Select -First 1).repo + $repositories = (git -C $dir remote -v | + sls "^(?\w+)\s+https://github.com/(?\S+)(?:.git)?").Matches | select -Unique | + % { [PSCustomObject]@{ repo = [String]$_.Groups['repo']; remote = [String]$_.Groups['remote']}} + + Write-Verbose "Repos available: $($repositories.remote)" + + $new.name = ($repositories | ? remote -in $candidates | Select -First 1).repo + + # on error fallback to origin + if($new.name) + { + Write-Verbose "Chosen repo: $($new.name)" + } + else + { + if ('origin' -in $repositories.remote) + { + $new.name = ($repositories | ? remote -eq 'origin' | Select -First 1).repo + } + else + { + $new.name = $repositories[0].repo + } + + Write-Verbose "Cannot track commit: falling back to $($new.name)" + } # get the path $new.path = git -C $dir rev-parse --show-toplevel @@ -183,6 +227,8 @@ $repos = New-Object -TypeName Repositories # Script to process the files into entries $process = { + Write-Verbose "Processing file: $_" + $entry = @{} # keep the file as id $entry.id = $_ @@ -190,6 +236,7 @@ $process = { # Check if the file should be excluded if($excludes.Exclude($_)) { + Write-Verbose "Excluding file using database: $_" return } @@ -208,6 +255,7 @@ $process = { { # If there is no repo ignore and update exclude $excludes.Add($_) + Write-Verbose "Excluding file for lack of repo: $_" return } } @@ -219,6 +267,7 @@ $process = { # propagate $entry = [PSCustomObject]$entry Write-Output $entry + Write-Verbose "New path entry: $entry" } foreach ($pdbfile in $pdbs) @@ -259,4 +308,5 @@ SRCSRV: source files --------------------------------------- # incorporate the stream into the file & $pdbstr -w "-p:$pdbfile" -s:srcsrv "-i:$tmp" + Write-Verbose "Stream check: & `"$pdbstr`" -r -p:`"$pdbfile`" -s:srcsrv" } From 7465b7ecf9e7f1ae76a16e76a3ef9cd7c44e6792 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Thu, 19 Jan 2023 01:02:29 +0100 Subject: [PATCH 30/49] Refs 16497. fixing clang/OS X errors Signed-off-by: Miguel Barro --- .github/workflows/reusable-github-ci.yml | 2 -- include/xtypes/DynamicData.hpp | 9 +++++---- include/xtypes/DynamicDataImpl.hpp | 2 +- include/xtypes/StringType.hpp | 2 +- include/xtypes/UnionType.hpp | 6 +++--- test/add_source_listing.ps1 | 2 +- test/unitary/xtypes/dynamicdata_operators.cpp | 16 ++++++++-------- test/unitary/xtypes/primitive_types.cpp | 2 +- test/unitary/xtypes/struct_type.cpp | 2 +- 9 files changed, 21 insertions(+), 22 deletions(-) diff --git a/.github/workflows/reusable-github-ci.yml b/.github/workflows/reusable-github-ci.yml index 705e3d86..72e7a62a 100644 --- a/.github/workflows/reusable-github-ci.yml +++ b/.github/workflows/reusable-github-ci.yml @@ -247,8 +247,6 @@ jobs: cmake "-DCMAKE_INSTALL_PREFIX=$(Join-Path (pwd) install)" $cmakeargs -B build . "::endgroup::" - gci # TODO: remove this - # Show the args EchoArgs --build build "$Env:CONFIG_TYPE".split(" ") --target install -j $Env:NUMBER_OF_PROCESSORS diff --git a/include/xtypes/DynamicData.hpp b/include/xtypes/DynamicData.hpp index b6dc1ac6..65b85768 100644 --- a/include/xtypes/DynamicData.hpp +++ b/include/xtypes/DynamicData.hpp @@ -767,8 +767,9 @@ class ReadableDynamicDataRef return static_cast(temp); } } + default: + return T(); } - return T(); } }; @@ -961,7 +962,7 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef "has_key method is only available for MapType."); const MapType& map = static_cast(type_); - const PairType& pair = static_cast(map.content_type()); + [[maybe_unused]] const PairType& pair = static_cast(map.content_type()); xtypes_assert(pair.first().is_compatible(key.type()) == TypeConsistency::EQUALS, "Key types doesn't match."); return map.has_key(instance_, p_instance(key)); } @@ -987,7 +988,7 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef xtypes_assert(type_.memory_size() == sizeof(T), "Incompatible types: '" << type_.name() << "' and '" << PrimitiveTypeKindTrait::name << "'."); - const EnumeratedType& enum_type = static_cast&>(type_); + [[maybe_unused]] const EnumeratedType& enum_type = static_cast&>(type_); xtypes_assert(enum_type.is_allowed_value(t), "Trying to set an invalid value for enumerated type '" << type_.name() << "'."); } @@ -1049,7 +1050,7 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef { xtypes_assert(type_.kind() == TypeKind::SEQUENCE_TYPE, "resize() is only available for sequence types but called for '" << type_.name() << "'."); - size_t bound = bounds(); + [[maybe_unused]] size_t bound = bounds(); xtypes_assert(!bound || bound >= size, "The desired size (" << size << ") is bigger than maximum allowed size for the type '" << type_.name() << "' (" << bounds() << ")."); diff --git a/include/xtypes/DynamicDataImpl.hpp b/include/xtypes/DynamicDataImpl.hpp index 02edb0f1..dd90d6c8 100644 --- a/include/xtypes/DynamicDataImpl.hpp +++ b/include/xtypes/DynamicDataImpl.hpp @@ -454,7 +454,7 @@ DYNAMIC_DATA_NUMERIC_INT_OPERATOR_IMPLEMENTATION(|); } #define DYNAMIC_DATA_PRIMITIVE_SELF_ASSIGN_OPERATOR_RESULT(OPERATOR) { \ - bool self_assign_valid = std::is_arithmetic::value && !std::is_same::value &&\ + [[maybe_unused]] bool self_assign_valid = std::is_arithmetic::value && !std::is_same::value &&\ !std::is_same::value && !std::is_same::value && !std::is_same::value;\ xtypes_assert(self_assign_valid,\ "Operator" << #OPERATOR << "=() cannot be used with non-arithmetic types");\ diff --git a/include/xtypes/StringType.hpp b/include/xtypes/StringType.hpp index 7fe289ef..8ac35315 100644 --- a/include/xtypes/StringType.hpp +++ b/include/xtypes/StringType.hpp @@ -109,7 +109,7 @@ class TStringType : public MutableCollectionType virtual void destroy_instance( uint8_t* instance) const override { - reinterpret_cast*>(instance)->std::basic_string::~basic_string(); + reinterpret_cast*>(instance)->~basic_string(); } virtual bool compare_instance( diff --git a/include/xtypes/UnionType.hpp b/include/xtypes/UnionType.hpp index 9d385ae4..d481d8a6 100644 --- a/include/xtypes/UnionType.hpp +++ b/include/xtypes/UnionType.hpp @@ -287,7 +287,7 @@ class UnionType : public AggregationType { if (other.kind() == TypeKind::ALIAS_TYPE) { - const AliasType& alias = static_cast(other); + [[maybe_unused]] const AliasType& alias = static_cast(other); xtypes_assert(alias.rget().kind() == TypeKind::UNION_TYPE, "Cannot copy data from different types: From '" << alias.rget().name() << "' to '" << name() << @@ -502,7 +502,7 @@ class UnionType : public AggregationType /// \brief This method verifies the validity of a given label. void check_label_value( - int64_t label) + [[maybe_unused]] int64_t label) { xtypes_assert(label != default_value_, "Label '" << label << "' is reserved."); DynamicType* type = &const_cast(disc()->type()); @@ -515,7 +515,7 @@ class UnionType : public AggregationType if (type->kind() == TypeKind::ENUMERATION_TYPE) { - EnumerationType* enum_type = static_cast*>(type); + [[maybe_unused]] EnumerationType* enum_type = static_cast*>(type); xtypes_assert( enum_type->is_allowed_value(label), "Value '" << label << "' isn't allowed by the discriminator enumeration '" << type->name() << "'"); diff --git a/test/add_source_listing.ps1 b/test/add_source_listing.ps1 index 67e9a9b0..64f250da 100644 --- a/test/add_source_listing.ps1 +++ b/test/add_source_listing.ps1 @@ -173,7 +173,7 @@ class Repositories { # filter out repo list $repositories = (git -C $dir remote -v | - sls "^(?\w+)\s+https://github.com/(?\S+)(?:.git)?").Matches | select -Unique | + sls "^(?\w+)\s+https://github.com/((?\S+)\.git|(?\S+))").Matches | select -Unique | % { [PSCustomObject]@{ repo = [String]$_.Groups['repo']; remote = [String]$_.Groups['remote']}} Write-Verbose "Repos available: $($repositories.remote)" diff --git a/test/unitary/xtypes/dynamicdata_operators.cpp b/test/unitary/xtypes/dynamicdata_operators.cpp index a13e5216..0aab4ea0 100644 --- a/test/unitary/xtypes/dynamicdata_operators.cpp +++ b/test/unitary/xtypes/dynamicdata_operators.cpp @@ -69,7 +69,7 @@ TEST (DynamicDataOperators, increment_decrement_operators) check_de_increment_operators(true, true); check_de_increment_operators('a', true); check_de_increment_operators('\n', true); - check_de_increment_operators('\u00f1', true); + check_de_increment_operators(u'\u00f1', true); check_de_increment_operators(PI, true); check_de_increment_operators(PI_D, true); check_de_increment_operators(PI_L, true); @@ -161,7 +161,7 @@ TEST (DynamicDataOperators, arithmetic_unary_operators) check_bitwise_complement_operator(true, true); check_bitwise_complement_operator('a', true); check_bitwise_complement_operator('\n', true); - check_bitwise_complement_operator('\u00f1', true); + check_bitwise_complement_operator(u'\u00f1', true); check_bitwise_complement_operator(7u, true); check_bitwise_complement_operator(10u, true); check_bitwise_complement_operator(20u, true); @@ -179,7 +179,7 @@ TEST (DynamicDataOperators, arithmetic_unary_operators) check_negate_operator(true, true); check_negate_operator('a', true); check_negate_operator('\n', true); - check_negate_operator('\u00f1', true); + check_negate_operator(u'\u00f1', true); check_negate_operator(7u, true); check_negate_operator(10u, true); check_negate_operator(20u, true); @@ -322,7 +322,7 @@ TEST (DynamicDataOperators, arithmetic_binary_operators) check_arithmetic_int_binary_operators(true, false, true); check_arithmetic_int_binary_operators('a', 'b', true); check_arithmetic_int_binary_operators('\n', 'b', true); - check_arithmetic_int_binary_operators('\u00f1', 'b', true); + check_arithmetic_int_binary_operators(u'\u00f1', 'b', true); #endif // Operators available (only floating-point) @@ -368,7 +368,7 @@ TEST (DynamicDataOperators, logical_operators) check_logical_not_operator(true); check_logical_not_operator('a'); check_logical_not_operator('\0'); - check_logical_not_operator('\u00f1'); + check_logical_not_operator(u'\u00f1'); check_logical_not_operator(1); check_logical_not_operator(1u); check_logical_not_operator(0); @@ -396,7 +396,7 @@ TEST (DynamicDataOperators, logical_operators) check_logical_binary_operator(true, false); check_logical_binary_operator('a', 'b'); check_logical_binary_operator('\n', '\0'); - check_logical_binary_operator('\u00f1', '\0'); + check_logical_binary_operator(u'\u00f1', '\0'); check_logical_binary_operator(1, -2); check_logical_binary_operator(1u, 2u); check_logical_binary_operator(4, 23); @@ -433,7 +433,7 @@ TEST (DynamicDataOperators, comparison_operators) check_comparison_binary_operator(true, false); check_comparison_binary_operator('a', 'b'); check_comparison_binary_operator('\n', '\0'); - check_comparison_binary_operator('\u00f1', '\0'); + check_comparison_binary_operator(u'\u00f1', '\0'); check_comparison_binary_operator(1, -2); check_comparison_binary_operator(1u, 2u); check_comparison_binary_operator(4, 23); @@ -584,7 +584,7 @@ TEST (DynamicDataOperators, assignment_operators) check_assignment_operators(true, false, true); check_assignment_operators('a', 'b', true); check_assignment_operators('\n', 'b', true); - check_assignment_operators('\u00f1', u'b', true); + check_assignment_operators(u'\u00f1', u'b', true); /* DynamicData a(primitive_type()); DynamicData b(primitive_type()); diff --git a/test/unitary/xtypes/primitive_types.cpp b/test/unitary/xtypes/primitive_types.cpp index 8e9a398a..86346760 100644 --- a/test/unitary/xtypes/primitive_types.cpp +++ b/test/unitary/xtypes/primitive_types.cpp @@ -29,7 +29,7 @@ static const uint64_t xUINT64 = 18446744073709551610ULL; static const float xFLOAT = 3.1415927410125732421875f; static const double xDOUBLE = 3.1415926535897931159979631875; static const char xCHAR = 'f'; -static const char16_t xCHAR16 = '\u00f1'; +static const char16_t xCHAR16 = u'\u00f1'; static const wchar_t xWCHAR = 34590; /********************************************* diff --git a/test/unitary/xtypes/struct_type.cpp b/test/unitary/xtypes/struct_type.cpp index ef568267..03b931cb 100644 --- a/test/unitary/xtypes/struct_type.cpp +++ b/test/unitary/xtypes/struct_type.cpp @@ -35,7 +35,7 @@ static const float xFLOAT = 3.1415927410125732421875f; static const double xDOUBLE = 3.1415926535897931159979631875; static const long double xLDOUBLE = 3.14159265358979321159979631875l; static const char xCHAR = 'f'; -static const char16_t xCHAR16 = '\u00f1'; +static const char16_t xCHAR16 = u'\u00f1'; static const wchar_t xWCHAR = 34590; static const std::string INNER_STRING_VALUE = "lay_down_and_cry"; From e1db3084738ae5131aabcd06aa86ada661da89a8 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 20 Jan 2023 11:41:13 +0100 Subject: [PATCH 31/49] Refs 16497. Fixing move semantics on DynamicData Signed-off-by: Miguel Barro --- include/xtypes/DynamicData.hpp | 20 +++++++++++++++++--- include/xtypes/MapInstance.hpp | 8 ++++---- include/xtypes/SequenceInstance.hpp | 8 ++++---- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/include/xtypes/DynamicData.hpp b/include/xtypes/DynamicData.hpp index 65b85768..4041e9e2 100644 --- a/include/xtypes/DynamicData.hpp +++ b/include/xtypes/DynamicData.hpp @@ -66,6 +66,16 @@ class ReadableDynamicDataRef { public: + ReadableDynamicDataRef(const ReadableDynamicDataRef& other) = default; + + ReadableDynamicDataRef(ReadableDynamicDataRef&& other) + : type_(other.type_) + , instance_(other.instance_) + , initialize_(other.initialize_) + { + other.initialize_ = false; + } + virtual ~ReadableDynamicDataRef() = default; /// \brief Deep equality operator. All DynamicData tree will be evaluated for equality. @@ -619,6 +629,7 @@ class ReadableDynamicDataRef uint8_t* source) : type_(type.kind() == TypeKind::ALIAS_TYPE ? static_cast(type).rget() : type) , instance_(source) + , initialize_(true) { } @@ -1349,8 +1360,8 @@ class DynamicData : public WritableDynamicDataRef : WritableDynamicDataRef(other.type_, new uint8_t[other.type_.memory_size()]) { memset(instance_, 0, other.type().memory_size()); - type_.move_instance(instance_, p_instance(other), initialize_); - initialize_ = true; + type_.move_instance(instance_, p_instance(other), false); + other.initialize_ = false; } /// \brief Assignment operator @@ -1562,7 +1573,10 @@ class DynamicData : public WritableDynamicDataRef virtual ~DynamicData() override { - type_.destroy_instance(instance_); + if(initialize_) + { + type_.destroy_instance(instance_); + } delete[] instance_; } diff --git a/include/xtypes/MapInstance.hpp b/include/xtypes/MapInstance.hpp index b7889a0c..8d18771e 100644 --- a/include/xtypes/MapInstance.hpp +++ b/include/xtypes/MapInstance.hpp @@ -199,10 +199,10 @@ class MapInstance friend class MapType; const PairType& content_; - uint32_t block_size_; - uint32_t capacity_; - uint8_t* memory_; - uint32_t size_; + uint32_t block_size_ = 0; + uint32_t capacity_ = 0; + uint8_t* memory_ = nullptr; + uint32_t size_ = 0; void realloc( size_t desired_capacity, diff --git a/include/xtypes/SequenceInstance.hpp b/include/xtypes/SequenceInstance.hpp index 848a1dee..622691ca 100644 --- a/include/xtypes/SequenceInstance.hpp +++ b/include/xtypes/SequenceInstance.hpp @@ -189,10 +189,10 @@ class SequenceInstance friend class SequenceType; const DynamicType& content_; - uint32_t block_size_; - uint32_t capacity_; - uint8_t* memory_; - uint32_t size_; + uint32_t block_size_ = 0; + uint32_t capacity_ = 0; + uint8_t* memory_ = nullptr; + uint32_t size_ = 0; void realloc( size_t desired_capacity, From fed71effef5263db109bd561b180d51de8f76b17 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Sat, 21 Jan 2023 23:22:42 +0100 Subject: [PATCH 32/49] Refs 16497. Compile warnings as errors. Signed-off-by: Miguel Barro --- .github/workflows/reusable-github-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/reusable-github-ci.yml b/.github/workflows/reusable-github-ci.yml index 72e7a62a..4f71e95e 100644 --- a/.github/workflows/reusable-github-ci.yml +++ b/.github/workflows/reusable-github-ci.yml @@ -233,6 +233,7 @@ jobs: # Build $cmakeargs = @() + $cmakeargs += "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON" $cmakeargs += "-DENABLE_PDB_INDEXING=ON" $cmakeargs += "-DENABLE_WER=ON" $cmakeargs += "-DXTYPES_BUILD_TESTS=ON" From a10b7cebf41019659d6c06f629d64365812aa317 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Sun, 22 Jan 2023 01:58:28 +0100 Subject: [PATCH 33/49] Refs 16497. Fixing clang/OS X errors Signed-off-by: Miguel Barro --- include/xtypes/idl/parser.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 360d1afd..05aa4a92 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -73,7 +73,7 @@ #else # define EPROSIMA_PLATFORM_PREPROCESSOR "cpp -H" # define EPROSIMA_PLATFORM_PREPROCESSOR_STRATEGY preprocess_strategy::pipe_stdin -# define EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES "-I " +# define EPROSIMA_PLATFORM_PREPROCESSOR_INCLUDES "-I" # define EPROSIMA_PLATFORM_PREPROCESSOR_ERRORREDIR " 2>/dev/null" # define EPROSIMA_PLATFORM_PIPE_OPEN_FLAGS "r" #endif From e30d3b3c7d54559c065194268494bf0873b95fe1 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Sun, 22 Jan 2023 03:31:12 +0100 Subject: [PATCH 34/49] Refs 16497. Avoid using as primitive size_t whose definition is platform dependent. Signed-off-by: Miguel Barro --- test/unitary/parser/parser_test.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/unitary/parser/parser_test.cpp b/test/unitary/parser/parser_test.cpp index e5e02570..8e7ae951 100644 --- a/test/unitary/parser/parser_test.cpp +++ b/test/unitary/parser/parser_test.cpp @@ -1318,16 +1318,20 @@ TEST (IDLParser, union_tests) data["wstr_b"] = L"Testing Wstring"; EXPECT_EQ(data.d().value(), 1); - EXPECT_EQ(data["union_c"].d().value(), static_cast(default_union_label(sizeof(uint64_t)))); + EXPECT_EQ(data["union_c"].d().value(), static_cast(default_union_label(sizeof(uint64_t)))); data["union_c"]["my_string"] = "Correct"; + data["union_c"]["my_float"] = 3.14f; - EXPECT_EQ(data["union_c"].d().value(), 2); + EXPECT_EQ(data["union_c"].d().value(), 2); + data["union_c"].d(3); - EXPECT_EQ(data["union_c"].d().value(), 3); + EXPECT_EQ(data["union_c"].d().value(), 3); + data["union_c"]["my_uint64"] = UINT64_C(314); - EXPECT_EQ(data["union_c"].d().value(), 1); - data["union_c"]["my_int32"] = 314; - EXPECT_EQ(data["union_c"].d().value(), 0); + EXPECT_EQ(data["union_c"].d().value(), 1); + + data["union_c"]["my_int32"] = INT32_C(314); + EXPECT_EQ(data["union_c"].d().value(), 0); const UnionType& test_union = context.module().union_switch("TestUnion"); DynamicData data_2(test_union); From 8eae16520007b07facd60150370b0175fea0164a Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Sun, 22 Jan 2023 04:13:34 +0100 Subject: [PATCH 35/49] Refs 16497. Fixing assertion regex usage Signed-off-by: Miguel Barro --- test/unitary/xtypes/dynamicdata_operators.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/unitary/xtypes/dynamicdata_operators.cpp b/test/unitary/xtypes/dynamicdata_operators.cpp index 0aab4ea0..724ad838 100644 --- a/test/unitary/xtypes/dynamicdata_operators.cpp +++ b/test/unitary/xtypes/dynamicdata_operators.cpp @@ -226,7 +226,13 @@ inline void check_arithmetic_flt_binary_operators( #define ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP_EXCEPT(OPERAND1, OPERATOR, OPERAND2, RES) \ {\ std::stringstream errmsg;\ - errmsg << "Operator" << (#OPERATOR[0] == '^' ? "\\^" : #OPERATOR);\ + char op = #OPERATOR[0];\ + errmsg << "Operator";\ + if(op == '^' || op == '|')\ + {\ + errmsg << "\\";\ + }\ + errmsg << op;\ ASSERT_OR_EXCEPTION(\ { ASSERT_EQ_DYNAMICDATA_ARITHMETIC_OP(OPERAND1, OPERATOR, OPERAND2, RES);},\ errmsg.str());\ From bfdd7ae4f7d7779247305325845bb778b5037749 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Sun, 22 Jan 2023 04:27:01 +0100 Subject: [PATCH 36/49] Refs 16497. Nightly CI Signed-off-by: Miguel Barro --- .github/workflows/nightly-ci.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/nightly-ci.yml diff --git a/.github/workflows/nightly-ci.yml b/.github/workflows/nightly-ci.yml new file mode 100644 index 00000000..da1075b5 --- /dev/null +++ b/.github/workflows/nightly-ci.yml @@ -0,0 +1,15 @@ +name: Nightly CI for eProsima xTypes + +on: + schedule: + - cron: '42 23 * * *' + +jobs: + xtypes_CI: + uses: ./.github/workflows/reusable-github-ci.yml + with: + label: "Nightly-CI" + os: "[\"ubuntu-latest\",\"windows-latest\",\"macos-latest\"]" + config: "[\"RelWithDebInfo\"]" + vs_toolset: "[\"v143\",\"v142\"]" + cmake_args: "[\"-DXTYPES_EXCEPTIONS=ON\",\"-DXTYPES_EXCEPTIONS=OFF\"]" From 8d2443a4561f34f310c8252d89c5941c2eec9627 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Mon, 23 Jan 2023 20:43:51 +0100 Subject: [PATCH 37/49] Fix c++20 compatibility issues Signed-off-by: Miguel Barro --- include/xtypes/DynamicDataImpl.hpp | 29 ++++++---- include/xtypes/StringConversion.hpp | 29 ++++++---- include/xtypes/UnionType.hpp | 7 ++- include/xtypes/idl/generator.hpp | 13 ++--- include/xtypes/idl/parser.hpp | 16 ++++-- test/unitary/xtypes/string_conversion.cpp | 68 +++++------------------ 6 files changed, 70 insertions(+), 92 deletions(-) diff --git a/include/xtypes/DynamicDataImpl.hpp b/include/xtypes/DynamicDataImpl.hpp index dd90d6c8..46fe8495 100644 --- a/include/xtypes/DynamicDataImpl.hpp +++ b/include/xtypes/DynamicDataImpl.hpp @@ -145,11 +145,13 @@ inline std::string ReadableDynamicDataRef::to_string() const ss << "<" << type_name << "> " << node.data().value(); break; case TypeKind::CHAR_16_TYPE: - ss << "<" << type_name << "> " << node.data().value(); - break; case TypeKind::WIDE_CHAR_TYPE: - ss << "<" << type_name << "> " << node.data().value(); - break; + { + ss << "<" << type_name << "> "; + auto aux = code_conversion_tool(std::u16string(1, node.data().value())); + ss << std::string(aux.begin(), aux.end()); + break; + } case TypeKind::INT_8_TYPE: ss << "<" << type_name << "> " << node.data().value(); break; @@ -187,13 +189,20 @@ inline std::string ReadableDynamicDataRef::to_string() const ss << "<" << type_name << "> " << node.data().value(); break; case TypeKind::WSTRING_TYPE: - ss << "<" << type_name << "> "; - ss << code_conversion_tool(node.data().value()); - break; + { + ss << "<" << type_name << "> "; + auto aux = node.data().value(); + auto aux2 = code_conversion_tool(std::u16string(aux.begin(), aux.end())); + ss << std::string(aux2.begin(), aux2.end()); + break; + } case TypeKind::STRING16_TYPE: - ss << "<" << type_name << "> "; - ss << code_conversion_tool(node.data().value()); - break; + { + ss << "<" << type_name << "> "; + auto aux = code_conversion_tool(node.data().value()); + ss << std::string(aux.begin(), aux.end()); + break; + } case TypeKind::ARRAY_TYPE: ss << "<" << type_name << ">"; break; diff --git a/include/xtypes/StringConversion.hpp b/include/xtypes/StringConversion.hpp index d50da038..91d495e1 100644 --- a/include/xtypes/StringConversion.hpp +++ b/include/xtypes/StringConversion.hpp @@ -19,6 +19,15 @@ #define EPROSIMA_STRING_CONVERSION_HPP_ #include +#include + +#ifdef __cpp_char8_t +# define XTYPES_CHAR char8_t +# define XTYPES_CHAR_LITERAL(text) u8 ## text +#else +# define XTYPES_CHAR char +# define XTYPES_CHAR_LITERAL(text) text +#endif namespace eprosima { @@ -31,19 +40,19 @@ struct choose_codecvt; template struct choose_codecvt_base { - using cvt = std::codecvt; + using cvt = std::codecvt; }; template -struct choose_codecvt +struct choose_codecvt : choose_codecvt_base { template static std::codecvt_base::result translate(const facet& f, std::mbstate_t& state, - const char* from, - const char* from_end, - const char*& from_next, + const XTYPES_CHAR* from, + const XTYPES_CHAR* from_end, + const XTYPES_CHAR*& from_next, wchar* to, wchar* to_end, wchar*& to_next) @@ -53,7 +62,7 @@ struct choose_codecvt }; template -struct choose_codecvt +struct choose_codecvt : choose_codecvt_base { template @@ -62,9 +71,9 @@ struct choose_codecvt const wchar* from, const wchar* from_end, const wchar*& from_next, - char* to, - char* to_end, - char*& to_next) + XTYPES_CHAR* to, + XTYPES_CHAR* to_end, + XTYPES_CHAR*& to_next) { return f.out(state, from, from_end, from_next, to, to_end, to_next); } @@ -80,7 +89,7 @@ std::basic_string code_conversion_tool(const std::basic_string_view& in using choose = choose_codecvt; locale loc; - // on mac STL ALL codecvt partial specializations use char as external type + // on mac STL ALL codecvt partial specializations use XTYPES_CHAR as external type auto& conv_facet = use_facet(loc); const unsigned int buffer_size = 64; diff --git a/include/xtypes/UnionType.hpp b/include/xtypes/UnionType.hpp index d481d8a6..cd8489f1 100644 --- a/include/xtypes/UnionType.hpp +++ b/include/xtypes/UnionType.hpp @@ -1066,7 +1066,8 @@ class UnionType : public AggregationType break; case TypeKind::CHAR_16_TYPE: { - std::u16string wstr = code_conversion_tool(label); + std::basic_string aux(label.begin(), label.end()); + auto wstr = code_conversion_tool(aux); char16_t value; // Check if comes with "'" if (label.size() == 1) @@ -1082,8 +1083,10 @@ class UnionType : public AggregationType break; case TypeKind::WIDE_CHAR_TYPE: { + std::basic_string aux(label.begin(), label.end()); + auto aux2 = code_conversion_tool(aux); + std::wstring temp(aux2.begin(), aux2.end()); wchar_t value; - std::wstring temp = code_conversion_tool(label); // Check if comes with "'" if (label.size() == 1) { diff --git a/include/xtypes/idl/generator.hpp b/include/xtypes/idl/generator.hpp index 0e511e4c..dc66fbcc 100644 --- a/include/xtypes/idl/generator.hpp +++ b/include/xtypes/idl/generator.hpp @@ -24,8 +24,8 @@ #include #include #include -#include +#include #include #include @@ -239,17 +239,12 @@ inline std::string label_value( return ss.str(); } case TypeKind::CHAR_16_TYPE: - { - char16_t temp = static_cast(value); - std::stringstream ss; - ss << "L'" << temp << "'"; - return ss.str(); - } case TypeKind::WIDE_CHAR_TYPE: { - wchar_t temp = static_cast(value); + char16_t temp = static_cast(value); std::stringstream ss; - ss << "L'" << temp << "'"; + auto aux = code_conversion_tool(std::u16string(1, temp)); + ss << "L'" << std::string(aux.begin(), aux.end()) << "'"; return ss.str(); } case TypeKind::INT_8_TYPE: diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 05aa4a92..9b425871 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -1030,7 +1030,8 @@ class Parser context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_CHAR"), ast); } - std::u16string temp = code_conversion_tool(literal); + std::basic_string aux(literal.begin(), literal.end()); + auto temp = code_conversion_tool(aux); data = temp[0]; break; } @@ -1041,7 +1042,9 @@ class Parser context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_CHAR"), ast); } - std::wstring temp = code_conversion_tool(literal); + std::basic_string aux(literal.begin(), literal.end()); + auto aux2 = code_conversion_tool(aux); + std::wstring temp(aux2.begin(), aux2.end()); data = temp[0]; break; } @@ -1076,14 +1079,15 @@ class Parser context_->log(log::LogLevel::xWARNING, "UNEXPECTED_LITERAL", message("WIDE_STRING"), ast); } - std::wstring value = code_conversion_tool(aux); - data = value; + std::basic_string aux2(literal.begin(), literal.end()); + auto temp = code_conversion_tool(aux2); + data = std::wstring(temp.begin(), temp.end()); break; } case TypeKind::STRING16_TYPE: { - std::u16string temp = code_conversion_tool(literal); - data = temp; + std::basic_string aux(literal.begin(), literal.end()); + data = code_conversion_tool(aux); break; } case TypeKind::BOOLEAN_TYPE: diff --git a/test/unitary/xtypes/string_conversion.cpp b/test/unitary/xtypes/string_conversion.cpp index c3b735f8..c4d183c8 100644 --- a/test/unitary/xtypes/string_conversion.cpp +++ b/test/unitary/xtypes/string_conversion.cpp @@ -18,90 +18,48 @@ using namespace std; using namespace eprosima; -TEST (StringConversion, from_char_to_wchar_short) -{ - string short_str{"test"}; - wstring expected{L"test"}; - ASSERT_EQ(code_conversion_tool(short_str), expected); -} - -TEST (StringConversion, from_char_to_wchar_long) -{ - string long_str{"test"}; - wstring expected{L"test"}; - - for(int i = 0; i < 1000; ++i) - { - int car = i % 74 + 48; - long_str.append({static_cast(car)}); - expected.append({static_cast(car)}); - } - - ASSERT_EQ(code_conversion_tool(long_str), expected); -} - -TEST (StringConversion, from_wchar_to_char_short) -{ - wstring short_str{L"test"}; - string expected{"test"}; - ASSERT_EQ(code_conversion_tool(short_str), expected); -} - -TEST (StringConversion, from_wchar_to_char_long) -{ - wstring long_str{L"test"}; - string expected{"test"}; - - for(int i = 0; i < 1000; ++i) - { - int car = i % 74 + 48; - long_str.append({static_cast(car)}); - expected.append({static_cast(car)}); - } - - ASSERT_EQ(code_conversion_tool(long_str), expected); -} +#define MBSTRING(name, text) std::basic_string name{XTYPES_CHAR_LITERAL(text)}; -TEST (StringConversion, from_char_to_char16_short) +TEST (StringConversion, from_utf8_to_utf16_short) { - string short_str{"test"}; + MBSTRING(short_str, "test") u16string expected{u"test"}; ASSERT_EQ(code_conversion_tool(short_str), expected); } -TEST (StringConversion, from_char_to_char16_long) +TEST (StringConversion, from_utf8_to_utf16_long) { - string long_str{"test"}; + MBSTRING(long_str, "test") u16string expected{u"test"}; for(int i = 0; i < 1000; ++i) { int car = i % 74 + 48; - long_str.append({static_cast(car)}); + long_str.append({static_cast(car)}); expected.append({static_cast(car)}); } ASSERT_EQ(code_conversion_tool(long_str), expected); } -TEST (StringConversion, from_char16_to_char_short) +TEST (StringConversion, from_utf16_to_utf8_short) { u16string short_str{u"test"}; - string expected{"test"}; - ASSERT_EQ(code_conversion_tool(short_str), expected); + MBSTRING(expected, "test") + ASSERT_EQ(code_conversion_tool(short_str), expected); } -TEST (StringConversion, from_char16_to_char_long) +TEST (StringConversion, from_utf16_to_utf8_long) { u16string long_str{u"test"}; - string expected{"test"}; + MBSTRING(expected, "test") for(int i = 0; i < 1000; ++i) { int car = i % 74 + 48; long_str.append({static_cast(car)}); - expected.append({static_cast(car)}); + expected.append({static_cast(car)}); } - ASSERT_EQ(code_conversion_tool(long_str), expected); + ASSERT_EQ(code_conversion_tool(long_str), expected); } From cb250403ac0a72869071df85a21148d72eec2dff Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 24 Jan 2023 16:20:24 +0100 Subject: [PATCH 38/49] Refs 16497. Fix C++20 compatibility issues Signed-off-by: Miguel Barro --- .github/workflows/ci.yml | 2 +- .github/workflows/nightly-ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e1392fa..84afe71f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,4 +28,4 @@ jobs: os: "[\"ubuntu-latest\",\"windows-latest\",\"macos-latest\"]" config: "[\"RelWithDebInfo\"]" vs_toolset: "[\"v143\",\"v142\"]" - cmake_args: "[\"-DXTYPES_EXCEPTIONS=ON\",\"-DXTYPES_EXCEPTIONS=OFF\"]" + cmake_args: "[\"-DXTYPES_EXCEPTIONS=ON\",\"-DCMAKE_CXX_STANDARD=20\"]" diff --git a/.github/workflows/nightly-ci.yml b/.github/workflows/nightly-ci.yml index da1075b5..d9802830 100644 --- a/.github/workflows/nightly-ci.yml +++ b/.github/workflows/nightly-ci.yml @@ -12,4 +12,4 @@ jobs: os: "[\"ubuntu-latest\",\"windows-latest\",\"macos-latest\"]" config: "[\"RelWithDebInfo\"]" vs_toolset: "[\"v143\",\"v142\"]" - cmake_args: "[\"-DXTYPES_EXCEPTIONS=ON\",\"-DXTYPES_EXCEPTIONS=OFF\"]" + cmake_args: "[\"-DXTYPES_EXCEPTIONS=ON\",\"-DXTYPES_EXCEPTIONS=OFF\",\"-DCMAKE_CXX_STANDARD=20\"]" From 9b69a74473ceebc6cd1e01fb0c25b2a61a4677c4 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Wed, 25 Jan 2023 16:31:40 +0100 Subject: [PATCH 39/49] Refs 16497. Refactor to link DataType lifecycle to their associated objects. Fixes issue #105 Signed-off-by: Miguel Barro --- CMakeLists.txt | 4 + include/xtypes/AliasType.hpp | 4 +- include/xtypes/ArrayType.hpp | 4 +- include/xtypes/DynamicData.hpp | 288 +++++++++++++----------- include/xtypes/DynamicDataImpl.hpp | 38 ++-- include/xtypes/DynamicType.hpp | 96 ++++---- include/xtypes/EnumeratedType.hpp | 19 +- include/xtypes/MapInstance.hpp | 62 +++-- include/xtypes/MapType.hpp | 6 +- include/xtypes/PairType.hpp | 29 +-- include/xtypes/PrimitiveType.hpp | 26 ++- include/xtypes/SequenceInstance.hpp | 56 +++-- include/xtypes/SequenceType.hpp | 4 +- include/xtypes/StringType.hpp | 4 +- include/xtypes/StructType.hpp | 4 +- include/xtypes/UnionType.hpp | 4 +- test/unitary/xtypes/primitive_types.cpp | 23 ++ 17 files changed, 371 insertions(+), 300 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3d4a48f..6c6b058d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,10 @@ macro(compile_test) compile_example(${TEST_NAME} SOURCE ${TEST_SOURCE}) +if(MSVC) + target_compile_options(${TEST_NAME} PRIVATE /bigobj) +endif(MSVC) + target_link_libraries(${TEST_NAME} PRIVATE GTest::gtest diff --git a/include/xtypes/AliasType.hpp b/include/xtypes/AliasType.hpp index f4301148..1aade1fc 100644 --- a/include/xtypes/AliasType.hpp +++ b/include/xtypes/AliasType.hpp @@ -177,9 +177,9 @@ class AliasType : public DynamicType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new AliasType(*this); + return std::make_shared(*this); } private: diff --git a/include/xtypes/ArrayType.hpp b/include/xtypes/ArrayType.hpp index 9b1b0fc6..62efd0c5 100644 --- a/include/xtypes/ArrayType.hpp +++ b/include/xtypes/ArrayType.hpp @@ -319,9 +319,9 @@ class ArrayType : public CollectionType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new ArrayType(*this); + return std::make_shared(*this); } private: diff --git a/include/xtypes/DynamicData.hpp b/include/xtypes/DynamicData.hpp index 4041e9e2..de5d7fe5 100644 --- a/include/xtypes/DynamicData.hpp +++ b/include/xtypes/DynamicData.hpp @@ -69,7 +69,7 @@ class ReadableDynamicDataRef ReadableDynamicDataRef(const ReadableDynamicDataRef& other) = default; ReadableDynamicDataRef(ReadableDynamicDataRef&& other) - : type_(other.type_) + : type_(std::move(other.type_)) , instance_(other.instance_) , initialize_(other.initialize_) { @@ -82,13 +82,13 @@ class ReadableDynamicDataRef bool operator == ( const ReadableDynamicDataRef& other) const { - if (type_.kind() == TypeKind::ARRAY_TYPE) + if (type_->kind() == TypeKind::ARRAY_TYPE) { // If the data is Array, a fast way to discard equality is that the content or size of the array // is different. We can check both without casting the type by comparing the type (array) name. - return type_.name() == other.type().name() && type_.compare_instance(instance_, other.instance_); + return type_->name() == other.type().name() && type_->compare_instance(instance_, other.instance_); } - return type_.compare_instance(instance_, other.instance_); + return type_->compare_instance(instance_, other.instance_); } /// \brief Deep inequality operator. Inverse of == operator. @@ -110,7 +110,7 @@ class ReadableDynamicDataRef /// \returns a reference to the representing DynamicType const DynamicType& type() const { - return type_; + return *type_; } /// \brief Returns the id of the managed instance. @@ -130,18 +130,18 @@ class ReadableDynamicDataRef template > const T& value() const { - xtypes_assert((type_.kind() == TypeKind::STRING_TYPE && std::is_same::value) - || (type_.kind() == TypeKind::WSTRING_TYPE && std::is_same::value) - || (type_.kind() == TypeKind::STRING16_TYPE && std::is_same::value) - || (type_.kind() == primitive_type().kind()) - || (type_.is_enumerated_type()), - "Expected type '" << type_.name() + xtypes_assert((type_->kind() == TypeKind::STRING_TYPE && std::is_same::value) + || (type_->kind() == TypeKind::WSTRING_TYPE && std::is_same::value) + || (type_->kind() == TypeKind::STRING16_TYPE && std::is_same::value) + || (type_->kind() == primitive_type().kind()) + || (type_->is_enumerated_type()), + "Expected type '" << type_->name() << "' but '" << PrimitiveTypeKindTrait::name << "' received while getting value."); - if (type_.is_enumerated_type()) + if (type_->is_enumerated_type()) { - xtypes_assert(type_.memory_size() == sizeof(T), - "Incompatible types: '" << type_.name() << "' and '" + xtypes_assert(type_->memory_size() == sizeof(T), + "Incompatible types: '" << type_->name() << "' and '" << PrimitiveTypeKindTrait::name << "'."); } @@ -182,25 +182,25 @@ class ReadableDynamicDataRef { size_t s_index(static_cast(index)); - xtypes_assert(type_.is_aggregation_type() || type_.is_collection_type() || type_.kind() == TypeKind::PAIR_TYPE, - "operator [size_t] isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type() || type_->is_collection_type() || type_->kind() == TypeKind::PAIR_TYPE, + "operator [size_t] isn't available for type '" << type_->name() << "'."); xtypes_assert(s_index < size(), "operator [" << s_index << "] is out of bounds."); - if (type_.is_collection_type()) + if (type_->is_collection_type()) { - const CollectionType& collection = static_cast(type_); + const CollectionType& collection = static_cast(*type_); // The following assert exists because it may be confusing by the user, it will return the pair instead of // the value associated to the "key" representation of the index. - xtypes_assert(type_.kind() != TypeKind::MAP_TYPE, "Cannot access a MapType by index"); + xtypes_assert(type_->kind() != TypeKind::MAP_TYPE, "Cannot access a MapType by index"); return ReadableDynamicDataRef(collection.content_type(), collection.get_instance_at(instance_, s_index)); } - xtypes_assert(type_.kind() != TypeKind::UNION_TYPE, "Members of UnionType cannot be accessed by index."); + xtypes_assert(type_->kind() != TypeKind::UNION_TYPE, "Members of UnionType cannot be accessed by index."); - if (type_.kind() == TypeKind::PAIR_TYPE) + if (type_->kind() == TypeKind::PAIR_TYPE) { xtypes_assert(s_index < 2, "operator[" << s_index << "] is out of bounds."); - const PairType& pair = static_cast(type_); + const PairType& pair = static_cast(*type_); if (s_index == 0) { return ReadableDynamicDataRef(pair.first(), instance_); @@ -211,7 +211,7 @@ class ReadableDynamicDataRef } } - const AggregationType& aggregation = static_cast(type_); + const AggregationType& aggregation = static_cast(*type_); const Member& member = aggregation.member(s_index); return ReadableDynamicDataRef(member.type(), instance_ + member.offset()); } @@ -221,8 +221,8 @@ class ReadableDynamicDataRef /// \return A readable reference of the discriminator. ReadableDynamicDataRef d() const { - xtypes_assert(type_.kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); - const UnionType& aggregation = static_cast(type_); + xtypes_assert(type_->kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); + const UnionType& aggregation = static_cast(*type_); const Member& member = aggregation.member(0); return ReadableDynamicDataRef(member.type(), instance_); } @@ -232,8 +232,8 @@ class ReadableDynamicDataRef /// \return The current selected member. const Member& current_case() const { - xtypes_assert(type_.kind() == TypeKind::UNION_TYPE, "current_case is only available for UnionType."); - const UnionType& aggregation = static_cast(type_); + xtypes_assert(type_->kind() == TypeKind::UNION_TYPE, "current_case is only available for UnionType."); + const UnionType& aggregation = static_cast(*type_); return aggregation.get_current_selection(instance_); } @@ -246,13 +246,13 @@ class ReadableDynamicDataRef ReadableDynamicDataRef data) const { xtypes_assert( - type_.kind() == TypeKind::MAP_TYPE, + type_->kind() == TypeKind::MAP_TYPE, "'at()' method is only available for MapType."); - const MapType& map = static_cast(type_); + const MapType& map = static_cast(*type_); const PairType& pair = static_cast(map.content_type()); uint8_t* instance = map.get_instance_at(instance_, data.instance_); - xtypes_assert(instance != nullptr, "MapType '" << type_.name() << "' doesn't contains the requested key."); + xtypes_assert(instance != nullptr, "MapType '" << type_->name() << "' doesn't contains the requested key."); return ReadableDynamicDataRef(pair.second(), instance + pair.first().memory_size()); } @@ -263,19 +263,19 @@ class ReadableDynamicDataRef /// \returns Element size of the DynamicData. size_t size() const { - xtypes_assert(type_.is_collection_type() || type_.is_aggregation_type() || type_.kind() == TypeKind::PAIR_TYPE, - "size() isn't available for type '" << type_.name() << "'."); - if (type_.is_collection_type()) + xtypes_assert(type_->is_collection_type() || type_->is_aggregation_type() || type_->kind() == TypeKind::PAIR_TYPE, + "size() isn't available for type '" << type_->name() << "'."); + if (type_->is_collection_type()) { - const CollectionType& collection = static_cast(type_); + const CollectionType& collection = static_cast(*type_); return collection.get_instance_size(instance_); } - if (type_.is_aggregation_type()) + if (type_->is_aggregation_type()) { - const AggregationType& aggregation = static_cast(type_); + const AggregationType& aggregation = static_cast(*type_); return aggregation.members().size(); } - if (type_.kind() == TypeKind::PAIR_TYPE) + if (type_->kind() == TypeKind::PAIR_TYPE) { return 2; } @@ -288,15 +288,15 @@ class ReadableDynamicDataRef /// If the DynamicData represents an Array, then bounds() == size() size_t bounds() const { - xtypes_assert(type_.is_collection_type(), - "bounds() isn't available for type '" << type_.name() << "'."); - if (type_.is_collection_type()) + xtypes_assert(type_->is_collection_type(), + "bounds() isn't available for type '" << type_->name() << "'."); + if (type_->is_collection_type()) { - if (type_.kind() == TypeKind::ARRAY_TYPE) + if (type_->kind() == TypeKind::ARRAY_TYPE) { return size(); } - const MutableCollectionType& collection = static_cast(type_); + const MutableCollectionType& collection = static_cast(*type_); return collection.bounds(); } return 0; @@ -304,7 +304,7 @@ class ReadableDynamicDataRef uint64_t hash() const { - return type_.hash(instance_); + return type_->hash(instance_); } /// \brief Returns a std::vector representing the underlying collection of types. @@ -313,16 +313,16 @@ class ReadableDynamicDataRef template > std::vector as_vector() const { - const CollectionType& collection = static_cast(type_); - xtypes_assert(type_.is_collection_type(), - "as_vector() isn't available for type '" << type_.name() << "'."); + const CollectionType& collection = static_cast(*type_); + xtypes_assert(type_->is_collection_type(), + "as_vector() isn't available for type '" << type_->name() << "'."); xtypes_assert((collection.content_type().kind() == TypeKind::STRING_TYPE && std::is_same::value) || (collection.content_type().kind() == TypeKind::WSTRING_TYPE && std::is_same::value) || (collection.content_type().kind() == TypeKind::STRING16_TYPE && std::is_same::value) || (collection.content_type().kind() == primitive_type().kind()), "as_vector<" << PrimitiveTypeKindTrait::name << ">() isn't available for type '" - << type_.name() << "'."); + << type_->name() << "'."); const T* location = reinterpret_cast(collection.get_instance_at(instance_, 0)); return std::vector(location, location + size()); @@ -408,10 +408,10 @@ class ReadableDynamicDataRef bool for_each( std::function visitor) const { - Instanceable::InstanceNode root(type_, instance_); + Instanceable::InstanceNode root(*type_, instance_); try { - type_.for_each_instance(root, [&](const Instanceable::InstanceNode& instance_node) + type_->for_each_instance(root, [&](const Instanceable::InstanceNode& instance_node) { visitor(ReadableNode(instance_node)); }); @@ -458,7 +458,7 @@ class ReadableDynamicDataRef ReadableDynamicDataRef operator * () const { - const CollectionType& collection = static_cast(type_); + const CollectionType& collection = static_cast(*type_); return ReadableDynamicDataRef(collection.content_type(), collection.get_instance_at(instance_, index_)); } @@ -489,7 +489,7 @@ class ReadableDynamicDataRef { } - const DynamicType& type_; + std::shared_ptr type_; uint8_t* instance_; size_t index_; }; @@ -499,8 +499,8 @@ class ReadableDynamicDataRef /// \returns The initial iterator. Iterator begin() const { - xtypes_assert(type_.is_collection_type(), - "begin() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_collection_type(), + "begin() isn't available for type '" << type_->name() << "'."); return Iterator(*this, false); } @@ -509,8 +509,8 @@ class ReadableDynamicDataRef /// \returns The final iterator. Iterator end() const { - xtypes_assert(type_.is_collection_type(), - "end() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_collection_type(), + "end() isn't available for type '" << type_->name() << "'."); return Iterator(*this, true); } @@ -561,7 +561,7 @@ class ReadableDynamicDataRef const MemberPair operator * () const { - const AggregationType& aggregation = static_cast(type_); + const AggregationType& aggregation = static_cast(*type_); return MemberPair( aggregation.member(index_), instance_ + aggregation.member(index_).offset()); @@ -583,15 +583,15 @@ class ReadableDynamicDataRef MemberIterator begin() const { - xtypes_assert(type_.is_aggregation_type(), - "begin() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "begin() isn't available for type '" << type_->name() << "'."); return MemberIterator(ref_, false); } MemberIterator end() const { - xtypes_assert(type_.is_aggregation_type(), - "end() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "end() isn't available for type '" << type_->name() << "'."); return MemberIterator(ref_, true); } @@ -617,8 +617,8 @@ class ReadableDynamicDataRef /// \returns An iterable representation of an aggregation dynamic data. MemberIterator items() const { - xtypes_assert(type_.is_aggregation_type(), - "items() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "items() isn't available for type '" << type_->name() << "'."); return MemberIterator(*this, false); } @@ -627,13 +627,29 @@ class ReadableDynamicDataRef ReadableDynamicDataRef( const DynamicType& type, uint8_t* source) - : type_(type.kind() == TypeKind::ALIAS_TYPE ? static_cast(type).rget() : type) - , instance_(source) + : instance_(source) , initialize_(true) { + const DynamicType* local = &type; + + if( type.kind() == TypeKind::ALIAS_TYPE ) + { + local = &static_cast(type).rget(); + } + + try + { + // is already associated to the DynamicData object + type_ = local->shared_from_this(); + } + catch(const std::bad_weak_ptr&) + { + // make a copy (if type changes may blow the DynamicData object) + type_ = local->clone(); + } } - const DynamicType& type_; + std::shared_ptr type_; uint8_t* instance_; bool initialize_ = false; @@ -650,14 +666,14 @@ class ReadableDynamicDataRef const std::string& member_name, bool read_only = true) const { - xtypes_assert(type_.is_aggregation_type(), - "operator [const std::string&] isn't available for type '" << type_.name() << "'."); - const AggregationType& aggregation = static_cast(type_); - xtypes_assert(type_.kind() != TypeKind::PAIR_TYPE, "PairType doesn't have operator [const std::string&]"); + xtypes_assert(type_->is_aggregation_type(), + "operator [const std::string&] isn't available for type '" << type_->name() << "'."); + const AggregationType& aggregation = static_cast(*type_); + xtypes_assert(type_->kind() != TypeKind::PAIR_TYPE, "PairType doesn't have operator [const std::string&]"); xtypes_assert(aggregation.has_member(member_name), - "Type '" << type_.name() << "' doesn't have a member named '" << member_name << "'."); + "Type '" << type_->name() << "' doesn't have a member named '" << member_name << "'."); - if (type_.kind() == TypeKind::UNION_TYPE) + if (type_->kind() == TypeKind::UNION_TYPE) { xtypes_assert( member_name != UNION_DISCRIMINATOR, @@ -679,10 +695,10 @@ class ReadableDynamicDataRef template > inline T _cast() const { - xtypes_assert(type_.is_primitive_type() || type_.is_enumerated_type(), + xtypes_assert(type_->is_primitive_type() || type_->is_enumerated_type(), "Expected a primitive type but '" << PrimitiveTypeKindTrait::name << "' received while casting data."); - switch (type_.kind()) + switch (type_->kind()) { case TypeKind::BOOLEAN_TYPE: { @@ -762,17 +778,17 @@ class ReadableDynamicDataRef case TypeKind::ENUMERATION_TYPE: { // For checking the associated_type, check for its memory_size - if (type_.memory_size() == sizeof(uint8_t)) + if (type_->memory_size() == sizeof(uint8_t)) { uint8_t temp = *this; return static_cast(temp); } - else if (type_.memory_size() == sizeof(uint16_t)) + else if (type_->memory_size() == sizeof(uint16_t)) { uint16_t temp = *this; return static_cast(temp); } - else if (type_.memory_size() == sizeof(uint32_t)) + else if (type_->memory_size() == sizeof(uint32_t)) { uint32_t temp = *this; return static_cast(temp); @@ -803,8 +819,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef WritableDynamicDataRef& operator = ( const WritableDynamicDataRef& other) { - type_.destroy_instance(instance_); - type_.copy_instance(instance_, p_instance(other)); + type_->destroy_instance(instance_); + type_->copy_instance(instance_, p_instance(other)); return *this; } @@ -895,8 +911,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef void d( int64_t disc) { - xtypes_assert(type_.kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); - UnionType& un = const_cast(static_cast(type_)); + xtypes_assert(type_->kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); + UnionType& un = const_cast(static_cast(*type_)); un.select_disc(instance_, disc); } @@ -907,8 +923,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef void d( ReadableDynamicDataRef disc) { - xtypes_assert(type_.kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); - UnionType& un = const_cast(static_cast(type_)); + xtypes_assert(type_->kind() == TypeKind::UNION_TYPE, "discriminator is only available for UnionType."); + UnionType& un = const_cast(static_cast(*type_)); un.select_disc(disc.type(), instance_, p_instance(disc)); } @@ -921,10 +937,10 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef ReadableDynamicDataRef data) { xtypes_assert( - type_.kind() == TypeKind::MAP_TYPE, + type_->kind() == TypeKind::MAP_TYPE, "operator[const DynamicData&] is only available for MapType."); - const MapType& map = static_cast(type_); + const MapType& map = static_cast(*type_); const PairType& pair = static_cast(map.content_type()); uint8_t* instance = map.get_instance_at(instance_, p_instance(data)); if (instance == nullptr) @@ -955,10 +971,10 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef ReadableDynamicDataRef data) const { xtypes_assert( - type_.kind() == TypeKind::MAP_TYPE, + type_->kind() == TypeKind::MAP_TYPE, "insert method is only available for MapType."); - const MapType& map = static_cast(type_); + const MapType& map = static_cast(*type_); xtypes_assert(map.content_type().is_compatible(data.type()) == TypeConsistency::EQUALS, "Types doesn't match"); return map.insert_instance(instance_, p_instance(data)) != nullptr; } @@ -969,10 +985,10 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef ReadableDynamicDataRef key) const { xtypes_assert( - type_.kind() == TypeKind::MAP_TYPE, + type_->kind() == TypeKind::MAP_TYPE, "has_key method is only available for MapType."); - const MapType& map = static_cast(type_); + const MapType& map = static_cast(*type_); [[maybe_unused]] const PairType& pair = static_cast(map.content_type()); xtypes_assert(pair.first().is_compatible(key.type()) == TypeConsistency::EQUALS, "Key types doesn't match."); return map.has_key(instance_, p_instance(key)); @@ -985,27 +1001,27 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef void value( const T& t) { - xtypes_assert((type_.kind() == TypeKind::STRING_TYPE && std::is_same::value) - || (type_.kind() == TypeKind::WSTRING_TYPE && std::is_same::value) - || (type_.kind() == TypeKind::STRING16_TYPE && std::is_same::value) - || (type_.kind() == PrimitiveTypeKindTrait::kind) - || (type_.is_enumerated_type()), - "Expected type '" << type_.name() + xtypes_assert((type_->kind() == TypeKind::STRING_TYPE && std::is_same::value) + || (type_->kind() == TypeKind::WSTRING_TYPE && std::is_same::value) + || (type_->kind() == TypeKind::STRING16_TYPE && std::is_same::value) + || (type_->kind() == PrimitiveTypeKindTrait::kind) + || (type_->is_enumerated_type()), + "Expected type '" << type_->name() << "' but '" << PrimitiveTypeKindTrait::name << "' received while setting value.", true); - if (type_.is_enumerated_type()) + if (type_->is_enumerated_type()) { - xtypes_assert(type_.memory_size() == sizeof(T), - "Incompatible types: '" << type_.name() << "' and '" + xtypes_assert(type_->memory_size() == sizeof(T), + "Incompatible types: '" << type_->name() << "' and '" << PrimitiveTypeKindTrait::name << "'."); - [[maybe_unused]] const EnumeratedType& enum_type = static_cast&>(type_); + [[maybe_unused]] const EnumeratedType& enum_type = static_cast&>(*type_); xtypes_assert(enum_type.is_allowed_value(t), - "Trying to set an invalid value for enumerated type '" << type_.name() << "'."); + "Trying to set an invalid value for enumerated type '" << type_->name() << "'."); } - type_.destroy_instance(instance_); - type_.copy_instance(instance_, reinterpret_cast(&t)); + type_->destroy_instance(instance_); + type_->copy_instance(instance_, reinterpret_cast(&t)); } /// \brief Push a primitive or string value into the DynamicData that represents a SequenceType @@ -1017,14 +1033,14 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef WritableDynamicDataRef& push( const T& t) // this = SequenceType { - xtypes_assert(type_.kind() == TypeKind::SEQUENCE_TYPE, - "push() is only available for sequence types but called for '" << type_.name() << "'."); - const SequenceType& sequence = static_cast(type_); + xtypes_assert(type_->kind() == TypeKind::SEQUENCE_TYPE, + "push() is only available for sequence types but called for '" << type_->name() << "'."); + const SequenceType& sequence = static_cast(*type_); xtypes_assert((sequence.content_type().kind() == TypeKind::STRING_TYPE && std::is_same::value) || (sequence.content_type().kind() == TypeKind::WSTRING_TYPE && std::is_same::value) || (sequence.content_type().kind() == TypeKind::STRING16_TYPE && std::is_same::value) || (sequence.content_type().kind() == primitive_type().kind()), - "Expected type '" << static_cast(type_).content_type().name() + "Expected type '" << static_cast(*type_).content_type().name() << "' but '" << PrimitiveTypeKindTrait::name << "' received while pushing value."); uint8_t* element = sequence.push_instance(instance_, reinterpret_cast(&t)); @@ -1040,9 +1056,9 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef WritableDynamicDataRef& push( const ReadableDynamicDataRef& data) // this = SequenceType { - xtypes_assert(type_.kind() == TypeKind::SEQUENCE_TYPE, - "push() is only available for sequence types but called for '" << type_.name() << "'."); - const SequenceType& sequence = static_cast(type_); + xtypes_assert(type_->kind() == TypeKind::SEQUENCE_TYPE, + "push() is only available for sequence types but called for '" << type_->name() << "'."); + const SequenceType& sequence = static_cast(*type_); uint8_t* element = sequence.push_instance(instance_, p_instance(data)); xtypes_assert(element != nullptr, "Bound limit reached while pushing value."); (void) element; @@ -1059,13 +1075,13 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef WritableDynamicDataRef& resize( size_t size) // this = SequenceType { - xtypes_assert(type_.kind() == TypeKind::SEQUENCE_TYPE, - "resize() is only available for sequence types but called for '" << type_.name() << "'."); + xtypes_assert(type_->kind() == TypeKind::SEQUENCE_TYPE, + "resize() is only available for sequence types but called for '" << type_->name() << "'."); [[maybe_unused]] size_t bound = bounds(); xtypes_assert(!bound || bound >= size, "The desired size (" << size << ") is bigger than maximum allowed size for the type '" - << type_.name() << "' (" << bounds() << ")."); - const SequenceType& sequence = static_cast(type_); + << type_->name() << "' (" << bounds() << ")."); + const SequenceType& sequence = static_cast(*type_); sequence.resize_instance(instance_, size); return *this; } @@ -1102,10 +1118,10 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef bool for_each( std::function visitor) { - Instanceable::InstanceNode root(type_, instance_); + Instanceable::InstanceNode root(*type_, instance_); try { - type_.for_each_instance(root, [&](const Instanceable::InstanceNode& instance_node) + type_->for_each_instance(root, [&](const Instanceable::InstanceNode& instance_node) { WritableNode node(instance_node); visitor(node); @@ -1199,7 +1215,7 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef MemberPair operator * () { - const AggregationType& aggregation = static_cast(type_); + const AggregationType& aggregation = static_cast(*type_); return MemberPair( aggregation.member(index_), instance_ + aggregation.member(index_).offset()); @@ -1257,8 +1273,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef /// \returns An iterable representation of an aggregation dynamic data. MemberIterator items() { - xtypes_assert(type_.is_aggregation_type(), - "items() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "items() isn't available for type '" << type_->name() << "'."); return MemberIterator(*this, false); } @@ -1267,8 +1283,8 @@ class WritableDynamicDataRef : public ReadableDynamicDataRef /// \returns An iterable representation of an aggregation dynamic data. ReadableDynamicDataRef::MemberIterator citems() { - xtypes_assert(type_.is_aggregation_type(), - "citems() isn't available for type '" << type_.name() << "'."); + xtypes_assert(type_->is_aggregation_type(), + "citems() isn't available for type '" << type_->name() << "'."); return ReadableDynamicDataRef::MemberIterator(*this, false); } @@ -1309,7 +1325,7 @@ class DynamicData : public WritableDynamicDataRef : WritableDynamicDataRef(type, new uint8_t[type.memory_size()]) { memset(instance_, 0, type.memory_size()); - type_.construct_instance(instance_); + type_->construct_instance(instance_); initialize_ = true; } @@ -1336,31 +1352,31 @@ class DynamicData : public WritableDynamicDataRef const DynamicType& type) : WritableDynamicDataRef(type, new uint8_t[type.memory_size()]) { - xtypes_assert(type_.is_compatible(other.type()) != TypeConsistency::NONE, + xtypes_assert(type_->is_compatible(other.type()) != TypeConsistency::NONE, "Incompatible types in DynamicData(const ReadableDynamicDataRef&, const DynamicType&): '" - << type_.name() << "' isn't compatible with '" << other.type().name() << "'."); + << type_->name() << "' isn't compatible with '" << other.type().name() << "'."); memset(instance_, 0, type.memory_size()); - type_.copy_instance_from_type(instance_, p_instance(other), other.type()); + type_->copy_instance_from_type(instance_, p_instance(other), other.type()); initialize_ = true; } /// \brief Copy constructor DynamicData( const DynamicData& other) - : WritableDynamicDataRef(other.type_, new uint8_t[other.type_.memory_size()]) + : WritableDynamicDataRef(*other.type_, new uint8_t[other.type_->memory_size()]) { memset(instance_, 0, other.type().memory_size()); - type_.copy_instance(instance_, p_instance(other)); + type_->copy_instance(instance_, p_instance(other)); initialize_ = true; } /// \brief Move constructor DynamicData( DynamicData&& other) - : WritableDynamicDataRef(other.type_, new uint8_t[other.type_.memory_size()]) + : WritableDynamicDataRef(*other.type_, new uint8_t[other.type_->memory_size()]) { memset(instance_, 0, other.type().memory_size()); - type_.move_instance(instance_, p_instance(other), false); + type_->move_instance(instance_, p_instance(other), false); other.initialize_ = false; } @@ -1368,11 +1384,11 @@ class DynamicData : public WritableDynamicDataRef DynamicData& operator = ( const DynamicData& other) { - xtypes_assert(type_.is_compatible(other.type()) == TypeConsistency::EQUALS, + xtypes_assert(type_->is_compatible(other.type()) == TypeConsistency::EQUALS, "Cannot assign DynamicData of type '" << other.type().name() << "' to DynamicData of type '" - << type_.name() << "'."); - type_.destroy_instance(instance_); - type_.copy_instance(instance_, p_instance(other)); + << type_->name() << "'."); + type_->destroy_instance(instance_); + type_->copy_instance(instance_, p_instance(other)); return *this; } @@ -1380,11 +1396,11 @@ class DynamicData : public WritableDynamicDataRef DynamicData& operator = ( ReadableDynamicDataRef other) { - xtypes_assert(type_.is_compatible(other.type()) == TypeConsistency::EQUALS, + xtypes_assert(type_->is_compatible(other.type()) == TypeConsistency::EQUALS, "Cannot assign DynamicData of type '" << other.type().name() << "' to DynamicData of type '" - << type_.name() << "'."); - type_.destroy_instance(instance_); - type_.copy_instance(instance_, p_instance(other)); + << type_->name() << "'."); + type_->destroy_instance(instance_); + type_->copy_instance(instance_, p_instance(other)); return *this; } @@ -1575,7 +1591,7 @@ class DynamicData : public WritableDynamicDataRef { if(initialize_) { - type_.destroy_instance(instance_); + type_->destroy_instance(instance_); } delete[] instance_; } diff --git a/include/xtypes/DynamicDataImpl.hpp b/include/xtypes/DynamicDataImpl.hpp index 46fe8495..02fd2a64 100644 --- a/include/xtypes/DynamicDataImpl.hpp +++ b/include/xtypes/DynamicDataImpl.hpp @@ -27,7 +27,7 @@ namespace xtypes { #define DYNAMIC_DATA_NUMERIC_SIGNED_INT_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::INT_8_TYPE:\ MACRO(int8_t, OPERATOR);\ @@ -39,14 +39,14 @@ namespace xtypes { MACRO(int64_t, OPERATOR);\ default:\ xtypes_assert(false,\ - "Operator" << #OPERATOR << "() isn't available for type '" << type_.name() << "'.");\ + "Operator" << #OPERATOR << "() isn't available for type '" << type_->name() << "'.");\ return *this;\ }\ } #define DYNAMIC_DATA_NUMERIC_INT_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::UINT_8_TYPE:\ MACRO(uint8_t, OPERATOR);\ @@ -63,7 +63,7 @@ namespace xtypes { #define DYNAMIC_DATA_NUMERIC_FLT_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::FLOAT_32_TYPE:\ MACRO(float, OPERATOR);\ @@ -89,7 +89,7 @@ namespace xtypes { #define DYNAMIC_DATA_BASICTYPE_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::CHAR_8_TYPE:\ MACRO(char, OPERATOR);\ @@ -106,7 +106,7 @@ namespace xtypes { #define DYNAMIC_DATA_BASICTYPE_INT_SWITCH(MACRO, OPERATOR) \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::CHAR_8_TYPE:\ MACRO(char, OPERATOR);\ @@ -236,29 +236,29 @@ inline std::string ReadableDynamicDataRef::to_string() const template<> inline std::string ReadableDynamicDataRef::cast() const { - xtypes_assert(type_.is_primitive_type() || - type_.kind() == TypeKind::STRING_TYPE || - type_.kind() == TypeKind::WSTRING_TYPE || - type_.kind() == TypeKind::STRING16_TYPE || - type_.is_enumerated_type(), - "Expected a primitive or string type but '" << type_.name() << "' received while casting data to 'std::string'."); + xtypes_assert(type_->is_primitive_type() || + type_->kind() == TypeKind::STRING_TYPE || + type_->kind() == TypeKind::WSTRING_TYPE || + type_->kind() == TypeKind::STRING16_TYPE || + type_->is_enumerated_type(), + "Expected a primitive or string type but '" << type_->name() << "' received while casting data to 'std::string'."); // Custom switch-case statement for types not contained in the macros - switch (type_.kind()) + switch (type_->kind()) { case TypeKind::ENUMERATION_TYPE: { // For checking the associated_type, check for its memory_size - if (type_.memory_size() == sizeof(uint8_t)) + if (type_->memory_size() == sizeof(uint8_t)) { uint8_t temp = *this; return std::to_string(temp); } - else if (type_.memory_size() == sizeof(uint16_t)) + else if (type_->memory_size() == sizeof(uint16_t)) { uint16_t temp = *this; return std::to_string(temp); } - else if (type_.memory_size() == sizeof(uint32_t)) + else if (type_->memory_size() == sizeof(uint32_t)) { uint32_t temp = *this; return std::to_string(temp); @@ -347,7 +347,7 @@ inline DynamicData& DynamicData::operator -- () inline bool DynamicData::operator ! () const { - switch(type_.kind()) + switch(type_->kind()) { case TypeKind::STRING_TYPE: return this->value().empty(); @@ -419,7 +419,7 @@ inline DynamicData DynamicData::operator OPERATOR (const ReadableDynamicDataRef& #define DYNAMIC_DATA_NUMERIC_SAFE_OPERATOR_IMPLEMENTATION(OPERATOR)\ inline DynamicData DynamicData::operator OPERATOR (const ReadableDynamicDataRef& other) const \ {\ - switch(type_.kind())\ + switch(type_->kind())\ {\ case TypeKind::CHAR_8_TYPE:\ case TypeKind::CHAR_16_TYPE:\ @@ -428,7 +428,7 @@ inline DynamicData DynamicData::operator OPERATOR (const ReadableDynamicDataRef& {\ std::ostringstream os;\ os << "Operator" << (#OPERATOR[0] == '^' ? "\\^" : #OPERATOR)\ - << " is not supported for type " << type_.name();\ + << " is not supported for type " << type_->name();\ throw std::runtime_error(os.str());\ }\ default:\ diff --git a/include/xtypes/DynamicType.hpp b/include/xtypes/DynamicType.hpp index 492d6980..fa633d83 100644 --- a/include/xtypes/DynamicType.hpp +++ b/include/xtypes/DynamicType.hpp @@ -24,12 +24,17 @@ #include #include +#include namespace eprosima { namespace xtypes { +class ReadableDynamicDataRef; +class SequenceInstance; + /// \brief Abstract base class for all dynamic types. -class DynamicType : public Instanceable +class DynamicType : public Instanceable, + public std::enable_shared_from_this { public: @@ -214,11 +219,14 @@ class DynamicType : public Instanceable /// \brief Deep clone of the DynamicType. /// \returns a new DynamicType without managing. - virtual DynamicType* clone() const = 0; + virtual std::shared_ptr clone() const = 0; TypeKind kind_; std::string name_; + friend class ReadableDynamicDataRef; + friend class SequenceInstance; + public: /// \brief Special managed pointer for DynamicTypes. @@ -228,35 +236,39 @@ class DynamicType : public Instanceable public: /// \brief Default initialization without pointer any type. - Ptr() - : type_(nullptr) - { - } + Ptr() = default; /// \brief Creates a copy of a DynamicType that will be managed. /// The copy is avoid if DynamnicType is primitive. - Ptr( - const DynamicType& type) - : type_(dont_clone_type(&type) ? &type : type.clone()) + Ptr(const DynamicType& type) { + try + { + if(dont_clone_type(&type)) + { + type_ = type.shared_from_this(); + return; + } + } + catch(const std::bad_weak_ptr&) {} + + // make a copy + type_ = type.clone(); } /// \brief Copy constructor. /// Makes an internal copy of the managed DynamicType. - /// The copy is avoid if DynamnicType is primitive. - Ptr( - const Ptr& ptr) - : type_(dont_clone_type(ptr.type_) ? ptr.type_ : ptr.type_->clone()) + /// The copy is avoid if DynamicType is primitive. + Ptr(const Ptr& ptr) { - } + if(!ptr.type_) + return; - Ptr( - Ptr&& ptr) - : type_(ptr.type_) - { - ptr.type_ = nullptr; + new (this) Ptr(*ptr.type_); } + Ptr(Ptr&& ptr) = default; + Ptr& operator = ( const Ptr& ptr) { @@ -265,24 +277,11 @@ class DynamicType : public Instanceable return *this; } - reset(); - type_ = dont_clone_type(ptr.type_) ? ptr.type_ : ptr.type_->clone(); + type_ = dont_clone_type(ptr.type_.get()) ? ptr.type_ : ptr.type_->clone(); return *this; } - Ptr& operator = ( - Ptr&& ptr) - { - if (type_ == ptr.type_) - { - return *this; - } - - reset(); - type_ = ptr.type_; - ptr.type_ = nullptr; - return *this; - } + Ptr& operator = ( Ptr&& ptr) = default; bool operator == ( const DynamicType::Ptr& ptr) const @@ -290,26 +289,11 @@ class DynamicType : public Instanceable return ptr.type_ == type_; } - virtual ~Ptr() - { - reset(); - } - - /// \brief Remove the managed DynamicType and points to nothing. - void reset() - { - if (!dont_clone_type(type_)) - { - delete type_; - } - type_ = nullptr; - } - /// \brief Free the internal managed DynamicType and points to nothing. - const DynamicType* free() + std::shared_ptr free() { - const DynamicType* freed = type_; - type_ = nullptr; + std::shared_ptr freed; + type_.swap(freed); return freed; } @@ -317,21 +301,21 @@ class DynamicType : public Instanceable /// \returns A pointer of the internal managed DynamicType. const DynamicType* get() const { - return type_; + return type_.get(); } /// \brief Returns a pointer of the internal managed DynamicType. /// \returns A pointer of the internal managed DynamicType. const DynamicType* operator ->() const { - return type_; + return type_.get(); } /// \brief Get a non-const pointer of the internal managed DynamicType. /// \returns A non-const pointer of the interal managed DynamicType DynamicType* operator ->() { - return const_cast(type_); + return const_cast(type_.get()); } /// \brief Returns a reference of the intenral managed DynamicType. @@ -343,7 +327,7 @@ class DynamicType : public Instanceable private: - const DynamicType* type_; + std::shared_ptr type_; static bool dont_clone_type( const DynamicType* type) diff --git a/include/xtypes/EnumeratedType.hpp b/include/xtypes/EnumeratedType.hpp index 8b35c670..6b4587f6 100644 --- a/include/xtypes/EnumeratedType.hpp +++ b/include/xtypes/EnumeratedType.hpp @@ -121,19 +121,20 @@ class EnumeratedType : public PrimitiveType return consistency; } -protected: - virtual DynamicType* clone() const override - { - EnumeratedType* result = new EnumeratedType(PrimitiveType::kind(), PrimitiveType::name()); - result->values_ = values_; - return result; - } - EnumeratedType( TypeKind kind, const std::string& name) - : PrimitiveType(kind, name) + : PrimitiveType(typename PrimitiveType::use_function_primitive_type{}, kind, name) + { + } + +protected: + + std::shared_ptr clone() const override { + auto clon = std::make_shared(this->kind(), this->name()); + clon->values_ = values_; + return clon; } /// \brief Insert a enumerator into the enumerated. diff --git a/include/xtypes/MapInstance.hpp b/include/xtypes/MapInstance.hpp index 8d18771e..305c0c08 100644 --- a/include/xtypes/MapInstance.hpp +++ b/include/xtypes/MapInstance.hpp @@ -37,11 +37,22 @@ class MapInstance MapInstance( const PairType& content, uint32_t capacity = 0) - : content_(content) - , block_size_(content.memory_size()) + : block_size_(content.memory_size()) , capacity_(capacity) , size_(0) { + std::shared_ptr tmp; + try + { + tmp = (content.shared_from_this()); + } + catch(const std::bad_weak_ptr&) + { + tmp = content.clone(); + } + + content_ = std::static_pointer_cast(std::move(tmp)); + init_memory(memory_, capacity_); } @@ -68,7 +79,7 @@ class MapInstance const MapInstance& other, uint32_t bounds) : content_(other.content_) - , block_size_(content_.memory_size()) + , block_size_(content_->memory_size()) , capacity_(bounds == 0 ? other.capacity_ : std::min(other.capacity_, bounds)) , size_(bounds == 0 ? other.size_ : std::min(other.size_, bounds)) { @@ -100,12 +111,12 @@ class MapInstance return false; } - if (content_.first().is_constructed_type() || content_.second().is_constructed_type()) + if (content_->first().is_constructed_type() || content_->second().is_constructed_type()) { bool comp = true; for (uint32_t i = 0; i < size_; i++) { - comp &= content_.compare_instance(memory_ + i * block_size_, other.memory_ + i * block_size_); + comp &= content_->compare_instance(memory_ + i * block_size_, other.memory_ + i * block_size_); } return comp; } @@ -135,7 +146,8 @@ class MapInstance } uint8_t* place = create_place(instance); - content_.first().copy_instance(place, instance); // Only copies the key + content_->first().copy_instance(place, instance); + content_->second().construct_instance(place + content_->first().memory_size()); size_++; @@ -184,10 +196,10 @@ class MapInstance { if (size_ > 0) { - uint64_t h = content_.hash(memory_); + uint64_t h = content_->hash(memory_); for (uint32_t i = 1; i < size_; ++i) { - Instanceable::hash_combine(h, content_.hash(get_element(i))); + Instanceable::hash_combine(h, content_->hash(get_element(i))); } return h; } @@ -198,7 +210,7 @@ class MapInstance friend class MapType; - const PairType& content_; + std::shared_ptr content_; uint32_t block_size_ = 0; uint32_t capacity_ = 0; uint8_t* memory_ = nullptr; @@ -235,7 +247,7 @@ class MapInstance memset(memory, 0, size * block_size_); for (uint32_t idx = 0; idx < size; ++idx) { - content_.construct_instance(memory + idx * block_size_); + content_->construct_instance(memory + idx * block_size_); } } } @@ -245,8 +257,8 @@ class MapInstance const MapInstance& other, uint32_t bounds) { - size_t other_first_size = other.content_.first().memory_size(); - size_t other_second_size = other.content_.second().memory_size(); + size_t other_first_size = other.content_->first().memory_size(); + size_t other_second_size = other.content_->second().memory_size(); // Check bytes to copy uint32_t min_capacity = std::min(capacity_, other.capacity_); @@ -268,17 +280,17 @@ class MapInstance realloc(min_size, bounds); } - if (content_.first().is_constructed_type() - || content_.second().is_constructed_type() - || content_.first().memory_size() != other_first_size - || content_.second().memory_size() != other_second_size) + if (content_->first().is_constructed_type() + || content_->second().is_constructed_type() + || content_->first().memory_size() != other_first_size + || content_->second().memory_size() != other_second_size) { for (uint32_t i = 0; i < min_size; i++) { - content_.copy_instance_from_type( + content_->copy_instance_from_type( memory_ + i * block_size_, - other.memory_ + i * other.content_.memory_size(), - other.content_); + other.memory_ + i * other.content_->memory_size(), + *other.content_); } } else //optimization when the pair are both primitive with same size @@ -295,7 +307,7 @@ class MapInstance { if (source != nullptr) { - if (content_.first().is_constructed_type() || content_.second().is_constructed_type()) + if (content_->first().is_constructed_type() || content_->second().is_constructed_type()) { if (overlap && check_overlap(target, source)) { @@ -303,7 +315,7 @@ class MapInstance uint32_t to_move = size_ - get_key_index(source); for (uint32_t i = to_move; i > 0; --i) { - content_.move_instance(target + (i - 1) * block_size_, source + (i - 1) * block_size_, true); + content_->move_instance(target + (i - 1) * block_size_, source + (i - 1) * block_size_, true); } } else @@ -311,7 +323,7 @@ class MapInstance // Moving full memory for (uint32_t i = 0; i < size_; ++i) { - content_.move_instance(target + i * block_size_, source + i * block_size_, true); + content_->move_instance(target + i * block_size_, source + i * block_size_, true); } } } @@ -438,18 +450,18 @@ class MapInstance uint64_t hash( const uint8_t* instance) const { - return content_.first().hash(instance); + return content_->first().hash(instance); } void free_memory() { if (memory_ != nullptr) { - if (content_.is_constructed_type()) + if (content_->is_constructed_type()) { for (int32_t i = capacity_ - 1; i >= 0; i--) { - content_.destroy_instance(memory_ + i * block_size_); + content_->destroy_instance(memory_ + i * block_size_); } } diff --git a/include/xtypes/MapType.hpp b/include/xtypes/MapType.hpp index cfed0691..d6bf8660 100644 --- a/include/xtypes/MapType.hpp +++ b/include/xtypes/MapType.hpp @@ -71,7 +71,7 @@ class MapType : public MutableCollectionType MapType( MapType&& other) = default; - virtual size_t memory_size() const override + size_t memory_size() const override { return sizeof(MapInstance); } @@ -250,9 +250,9 @@ class MapType : public MutableCollectionType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new MapType(*this); + return std::make_shared(*this); } }; diff --git a/include/xtypes/PairType.hpp b/include/xtypes/PairType.hpp index 056f0196..ba59729f 100644 --- a/include/xtypes/PairType.hpp +++ b/include/xtypes/PairType.hpp @@ -25,6 +25,8 @@ namespace eprosima { namespace xtypes { +class MapInstance; + class PairType : public DynamicType { public: @@ -80,19 +82,19 @@ class PairType : public DynamicType second_ = DynamicType::Ptr(std::move(second)); } - virtual size_t memory_size() const override + size_t memory_size() const override { return first_->memory_size() + second_->memory_size(); } - virtual void construct_instance( + void construct_instance( uint8_t* instance) const override { first_->construct_instance(instance); second_->construct_instance(instance + first_->memory_size()); } - virtual void copy_instance( + void copy_instance( uint8_t* target, const uint8_t* source) const override { @@ -100,7 +102,7 @@ class PairType : public DynamicType second_->copy_instance(target + first_->memory_size(), source + first_->memory_size()); } - virtual void copy_instance_from_type( + void copy_instance_from_type( uint8_t* target, const uint8_t* source, const DynamicType& arg_other) const override @@ -127,7 +129,7 @@ class PairType : public DynamicType second_->copy_instance_from_type(target + first_->memory_size(), source + first_->memory_size(), pair.second()); } - virtual void move_instance( + void move_instance( uint8_t* target, uint8_t* source, bool initialized) const override @@ -136,14 +138,14 @@ class PairType : public DynamicType second_->move_instance(target + first_->memory_size(), source + first_->memory_size(), initialized); } - virtual void destroy_instance( + void destroy_instance( uint8_t* instance) const override { first_->destroy_instance(instance); second_->destroy_instance(instance + first_->memory_size()); } - virtual bool compare_instance( + bool compare_instance( const uint8_t* instance, const uint8_t* other_instance) const override { @@ -152,7 +154,7 @@ class PairType : public DynamicType second_->compare_instance(instance + first_->memory_size(), other_instance + first_->memory_size()); } - virtual TypeConsistency is_compatible( + TypeConsistency is_compatible( const DynamicType& other) const override { if (other.kind() == TypeKind::ALIAS_TYPE) @@ -171,7 +173,7 @@ class PairType : public DynamicType return TypeConsistency::NONE; } - virtual void for_each_type( + void for_each_type( const TypeNode& node, TypeVisitor visitor) const override { @@ -191,7 +193,7 @@ class PairType : public DynamicType second_->for_each_type(s, visitor); } - virtual void for_each_instance( + void for_each_instance( const InstanceNode& node, InstanceVisitor visitor) const override { @@ -211,7 +213,7 @@ class PairType : public DynamicType second_->for_each_instance(s, visitor); } - virtual uint64_t hash( + uint64_t hash( const uint8_t* instance) const override { uint64_t h = first_->hash(instance); @@ -224,11 +226,12 @@ class PairType : public DynamicType DynamicType::Ptr first_; DynamicType::Ptr second_; - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new PairType(*this); + return std::make_shared(*this); } + friend class MapInstance; }; } // namespace xtypes diff --git a/include/xtypes/PrimitiveType.hpp b/include/xtypes/PrimitiveType.hpp index af4dfeff..2e32a73f 100644 --- a/include/xtypes/PrimitiveType.hpp +++ b/include/xtypes/PrimitiveType.hpp @@ -80,22 +80,30 @@ template class PrimitiveType : public DynamicType { protected: + // Avoid direct use of the class (there is a factory) + // Allow the use in subclasses + struct use_function_primitive_type {}; - template - friend const DynamicType& primitive_type(); +public: - PrimitiveType() + PrimitiveType(use_function_primitive_type) : DynamicType(PrimitiveTypeKindTrait::kind, PrimitiveTypeKindTrait::name) { } PrimitiveType( + use_function_primitive_type, TypeKind kind, const std::string& name) : DynamicType(kind, name) { } +protected: + + template + friend const DynamicType& primitive_type(); + PrimitiveType( const PrimitiveType& other) = delete; PrimitiveType( @@ -114,8 +122,8 @@ class PrimitiveType : public DynamicType virtual void destroy_instance( uint8_t* /*instance*/) const override - { - } //Default does nothing + { //Default does nothing + } virtual void copy_instance( uint8_t* target, @@ -267,11 +275,11 @@ class PrimitiveType : public DynamicType visitor(node); } - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new PrimitiveType(); - } + return std::make_shared>(use_function_primitive_type{}, this->kind(), this->name()); + } }; /// \brief Helper function to create a PrimitiveType. @@ -284,7 +292,7 @@ const DynamicType& primitive_type() // The creation of PrimitiveType must be always done // by this function in order to not broken the DynamicType::Ptr // optimizations for PrimitiveType - static PrimitiveType p; + static PrimitiveType p(typename PrimitiveType::use_function_primitive_type{}); return p; } diff --git a/include/xtypes/SequenceInstance.hpp b/include/xtypes/SequenceInstance.hpp index 622691ca..48779ec5 100644 --- a/include/xtypes/SequenceInstance.hpp +++ b/include/xtypes/SequenceInstance.hpp @@ -37,11 +37,21 @@ class SequenceInstance SequenceInstance( const DynamicType& content, uint32_t capacity = 0) - : content_(content) - , block_size_(content.memory_size()) + : block_size_(content.memory_size()) , capacity_(capacity) , size_(0) { + try + { + // is already associated to the DynamicData object + content_ = content.shared_from_this(); + } + catch(const std::bad_weak_ptr&) + { + // make a copy (if type changes may blow the DynamicData object) + content_ = content.clone(); + } + init_memory(memory_, capacity_); } @@ -69,11 +79,21 @@ class SequenceInstance const SequenceInstance& other, const DynamicType& content, uint32_t bounds) - : content_(content) - , block_size_(content.memory_size()) + : block_size_(content.memory_size()) , capacity_(bounds == 0 ? other.capacity_ : std::min(other.capacity_, bounds)) , size_(bounds == 0 ? other.size_ : std::min(other.size_, bounds)) { + try + { + // is already associated to the DynamicData object + content_ = content.shared_from_this(); + } + catch(const std::bad_weak_ptr&) + { + // make a copy (if type changes may blow the DynamicData object) + content_ = content.clone(); + } + init_memory(memory_, capacity_); if (memory_ != nullptr) @@ -102,12 +122,12 @@ class SequenceInstance return false; } - if (content_.is_constructed_type()) + if (content_->is_constructed_type()) { bool comp = true; for (uint32_t i = 0; i < size_; i++) { - comp &= content_.compare_instance(memory_ + i * block_size_, other.memory_ + i * block_size_); + comp &= content_->compare_instance(memory_ + i * block_size_, other.memory_ + i * block_size_); } return comp; } @@ -136,7 +156,7 @@ class SequenceInstance } uint8_t* place = memory_ + size_ * block_size_; - content_.copy_instance(place, instance); + content_->copy_instance(place, instance); size_++; @@ -160,7 +180,7 @@ class SequenceInstance for (size_t i = size_; i < new_size; i++) { uint8_t* place = memory_ + i * block_size_; - content_.construct_instance(place); + content_->construct_instance(place); } size_ = new_size; @@ -188,7 +208,7 @@ class SequenceInstance friend class SequenceType; - const DynamicType& content_; + std::shared_ptr content_; uint32_t block_size_ = 0; uint32_t capacity_ = 0; uint8_t* memory_ = nullptr; @@ -225,7 +245,7 @@ class SequenceInstance memset(memory, 0, size * block_size_); for (uint32_t idx = 0; idx < size; ++idx) { - content_.construct_instance(memory + idx * block_size_); + content_->construct_instance(memory + idx * block_size_); } } } @@ -235,7 +255,7 @@ class SequenceInstance const SequenceInstance& other, uint32_t bounds) { - size_t other_block_size = other.content_.memory_size(); + size_t other_block_size = other.content_->memory_size(); // Check bytes to copy uint32_t min_capacity = std::min(capacity_, other.capacity_); @@ -257,14 +277,14 @@ class SequenceInstance realloc(min_size, bounds); } - if (content_.is_constructed_type() || block_size_ != other_block_size) + if (content_->is_constructed_type() || block_size_ != other_block_size) { for (uint32_t i = 0; i < min_size; i++) { - content_.copy_instance_from_type( + content_->copy_instance_from_type( memory_ + i * block_size_, other.memory_ + i * other_block_size, - other.content_); + *other.content_); } } else //optimization when the type is primitive with same block_size @@ -280,11 +300,11 @@ class SequenceInstance { if (source != nullptr) { - if (content_.is_constructed_type()) + if (content_->is_constructed_type()) { for (uint32_t i = 0; i < size_; i++) { - content_.move_instance(target + i * block_size_, source + i * block_size_, true); + content_->move_instance(target + i * block_size_, source + i * block_size_, true); } } else //optimization when the type is primitive @@ -298,11 +318,11 @@ class SequenceInstance { if (memory_ != nullptr) { - if (content_.is_constructed_type()) + if (content_->is_constructed_type()) { for (int32_t i = capacity_ - 1; i >= 0; i--) { - content_.destroy_instance(memory_ + i * block_size_); + content_->destroy_instance(memory_ + i * block_size_); } } diff --git a/include/xtypes/SequenceType.hpp b/include/xtypes/SequenceType.hpp index c5c87c5c..84500a05 100644 --- a/include/xtypes/SequenceType.hpp +++ b/include/xtypes/SequenceType.hpp @@ -256,9 +256,9 @@ class SequenceType : public MutableCollectionType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new SequenceType(*this); + return std::make_shared(*this); } }; diff --git a/include/xtypes/StringType.hpp b/include/xtypes/StringType.hpp index 8ac35315..382949ba 100644 --- a/include/xtypes/StringType.hpp +++ b/include/xtypes/StringType.hpp @@ -186,9 +186,9 @@ class TStringType : public MutableCollectionType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new TStringType(*this); + return std::make_shared(*this); } }; diff --git a/include/xtypes/StructType.hpp b/include/xtypes/StructType.hpp index d7841e5d..6ee3ca1a 100644 --- a/include/xtypes/StructType.hpp +++ b/include/xtypes/StructType.hpp @@ -282,9 +282,9 @@ class StructType : public AggregationType protected: - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new StructType(*this); + return std::make_shared(*this); } private: diff --git a/include/xtypes/UnionType.hpp b/include/xtypes/UnionType.hpp index cd8489f1..65ba7586 100644 --- a/include/xtypes/UnionType.hpp +++ b/include/xtypes/UnionType.hpp @@ -465,9 +465,9 @@ class UnionType : public AggregationType friend ReadableDynamicDataRef; friend WritableDynamicDataRef; - virtual DynamicType* clone() const override + std::shared_ptr clone() const override { - return new UnionType(*this); + return std::make_shared(*this); } /// \brief This method adds the discriminator has the first member of the aggregation. diff --git a/test/unitary/xtypes/primitive_types.cpp b/test/unitary/xtypes/primitive_types.cpp index 86346760..0cb65c5a 100644 --- a/test/unitary/xtypes/primitive_types.cpp +++ b/test/unitary/xtypes/primitive_types.cpp @@ -193,6 +193,29 @@ TEST (PrimitiveTypes, primitive_type_int32_uint16) EXPECT_TRUE((singleCheck(55, 55))); } +// Comes from issue #105 +TEST(EnumerationType, stack_datatype_deleted) +{ + auto getTestEnum = [] + { + EnumerationType testEnum("TestEnum"); + testEnum.add_enumerator("item0"); + testEnum.add_enumerator("item1"); + testEnum.add_enumerator("item2"); + + DynamicData test(testEnum); + EXPECT_NO_THROW({test.to_string();}); + + DynamicData test2(test); + EXPECT_NO_THROW({test2.to_string();}); + + return test; + }; + + DynamicData testData(getTestEnum()); + EXPECT_NO_THROW({testData.to_string();}); +} + TEST(EnumerationType, enumeration_tests) { // Creation and expected operation From 87522f7eca182b2097fca689c0212f809b1ef859 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Thu, 26 Jan 2023 12:33:43 +0100 Subject: [PATCH 40/49] Refs 16497. Allow custom cpp-peglib version selection Signed-off-by: Miguel Barro --- CMakeLists.txt | 4 +++- README.md | 17 ++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c6b058d..792b168d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,8 @@ if(ENABLE_WER) set(WER_TIMEOUT_TIME 10) endif() +set(XTYPES_PEGLIB_VERSION "master" CACHE STRING "yhirose/cpp-peglib version to use.") + set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) @@ -57,7 +59,7 @@ endif() # Download the cpp-peglib header file needed file(DOWNLOAD - https://raw.githubusercontent.com/yhirose/cpp-peglib/master/peglib.h + https://raw.githubusercontent.com/yhirose/cpp-peglib/${XTYPES_PEGLIB_VERSION}/peglib.h ${PROJECT_BINARY_DIR}/thirdparty/cpp-peglib/peglib.h ) diff --git a/README.md b/README.md index 4bd799e1..149ef32a 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,6 @@ # xtypes Fast and lightweight C++17 header-only implementation of [OMG DDS-XTYPES](https://www.omg.org/spec/DDS-XTypes) standard. -To properly download this library, please consider cloning it using the `--recursive` options, as it includes the [cpp-peglib](https://github.com/yhirose/cpp-peglib) library as a submodule: - -```bash -git clone https://github.com/eProsima/xtypes.git --recursive -``` - - ## Getting Started Given the following IDL, @@ -72,6 +65,16 @@ Although there is no library generated by *xtypes*, you can do the linking with target_link_libraries(${PROJECT_NAME} xtypes) ``` +### cpp-peglib library version + +To link *xtypes* to a specific version of the [cpp-peglib](https://github.com/yhirose/cpp-peglib) a CMake +cache variable is provided: `XTYPES_PEGLIB_VERSION`. If not specified defaults to master. + +```bash +$ cmake .. -DXTYPES_PEGLIB_VERSION="v1.8.2" +$ make +``` + ### Examples To compile the examples located in the `examples/` folder, enable the `XTYPES_BUILD_EXAMPLES` cmake flag. Supposing you are in a `build` folder inside of `xtypes` top folder, you can run the following to compile the examples. From 2a6168a81d5586f08c326138350d793c4ad152e8 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Thu, 16 Feb 2023 08:45:19 +0100 Subject: [PATCH 41/49] Refs 16497. Added test StructType.russkel_issue Signed-off-by: Miguel Barro --- test/unitary/xtypes/struct_type.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/unitary/xtypes/struct_type.cpp b/test/unitary/xtypes/struct_type.cpp index 03b931cb..051de97f 100644 --- a/test/unitary/xtypes/struct_type.cpp +++ b/test/unitary/xtypes/struct_type.cpp @@ -534,3 +534,26 @@ TEST (StructType, copying_a_single_value_structure) EXPECT_EQ(str.value().compare("Hey!"), 0); } + +// References: https://github.com/eProsima/xtypes/pull/113#issuecomment-1430864724 + +StructType PGN_64750() +{ + StructType msg("Msg"); + msg.add_member("blade_elevation_deviation_left", primitive_type()); + msg.add_member("blade_elevation_deviation_right", primitive_type()); + msg.add_member("bld_reference_elevation_offset_left", primitive_type()); + msg.add_member("bld_rference_elevation_offset_right", primitive_type()); + + return msg; +} + +TEST (StructType, russkel_issue) +{ + DynamicData data(PGN_64750()); + + data["blade_elevation_deviation_left"] = uint16_t(42); + data["blade_elevation_deviation_right"] = data["blade_elevation_deviation_left"]; + data["bld_reference_elevation_offset_left"] = data["blade_elevation_deviation_right"]; + data["bld_rference_elevation_offset_right"] = data["bld_reference_elevation_offset_left"]; +} From 05c955aa0d12efe9e7e7085dd833a7b0d9b47be0 Mon Sep 17 00:00:00 2001 From: laura-eprosima Date: Mon, 14 Jun 2021 16:29:49 +0200 Subject: [PATCH 42/49] Fix some errors Signed-off-by: laura-eprosima --- include/xtypes/idl/Module.hpp | 17 ++++- include/xtypes/idl/generator.hpp | 2 +- include/xtypes/idl/parser.hpp | 104 +++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/include/xtypes/idl/Module.hpp b/include/xtypes/idl/Module.hpp index 24bfc712..864ff066 100644 --- a/include/xtypes/idl/Module.hpp +++ b/include/xtypes/idl/Module.hpp @@ -71,6 +71,11 @@ class Module return inner_[submodule]; } + size_t submodule_size() + { + return inner_.size(); + } + using ModuleVisitor = std::function; void for_each_submodule( @@ -589,9 +594,19 @@ class Module // Generic type retrieval. DynamicType::Ptr type( - const std::string& name) + const std::string& name, + bool recursive = false) { DynamicType::Ptr ret_type; + + if (recursive) + { + for (auto [key, mod]: inner_) + { + ret_type = mod.get()->type(name, recursive); + } + } + // Solve scope PairModuleSymbol module = resolve_scope(name); if (module.first == nullptr) diff --git a/include/xtypes/idl/generator.hpp b/include/xtypes/idl/generator.hpp index dc66fbcc..acce02f2 100644 --- a/include/xtypes/idl/generator.hpp +++ b/include/xtypes/idl/generator.hpp @@ -196,7 +196,7 @@ inline std::string type_name( { size_t scope_end = type_name.rfind("::"); std::string scope = type_name.substr(0, scope_end); - if (scope == node->module().scope()) // Redundant scope: get rid of it + if (node && (scope == node->module().scope())) // Redundant scope: get rid of it { ss << type_name.substr(scope_end + 2); } diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 9b425871..6d7210f6 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -678,6 +678,110 @@ class Parser l - CPP_PEGLIB_LINE_COUNT_ERROR) + ":" + std::to_string(c) + ")"); } + bool read_file( + const char* path, + std::vector& buff) const + { + std::ifstream ifs(path, std::ios::in | std::ios::binary); + + if (ifs.fail()) + { + context_->log(log::LogLevel::DEBUG, "FILE", + "Cannot open file: " + std::string(path)); + return false; + } + + buff.resize(static_cast(ifs.seekg(0, std::ios::end).tellg())); + + if (!buff.empty()) + { + ifs.seekg(0, std::ios::beg).read(&buff[0], static_cast(buff.size())); + } + context_->log(log::LogLevel::DEBUG, "FILE", + "Loaded file: " + std::string(path)); + return true; + } + + static std::string exec( + const std::string& cmd, + bool filter_stderr = true) + { + std::array buffer; + std::string command = cmd; + if (filter_stderr) + { + command.append(" 2> /dev/null"); + } + std::string result; + std::unique_ptr pipe(popen(command.c_str(), "r"), pclose); + if (!pipe) + { + throw std::runtime_error("popen() failed!"); + } + while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) + { + result += buffer.data(); + } + return result; + } + + void replace_all_string( + std::string& str, + const std::string& from, + const std::string& to) const + { + size_t froms = from.size(); + size_t tos = to.size(); + size_t pos = str.find(from); + const std::string escaped = "\\\\\""; + size_t escaped_size = escaped.size(); + while (pos != std::string::npos) + { + str.replace(pos, froms, to); + pos = str.find(from, pos + tos); + while (str[pos - 1] == '\\') + { + str.replace(pos, froms, escaped); + pos = str.find(from, pos + escaped_size); + } + + } + } + + std::string preprocess_string( + const std::string& idl_string) const + { + std::string args = "-H "; + for (const std::string inc_path : context_->include_paths) + { + args += "-I " + inc_path + " "; + } + // Escape double quotes inside the idl_string + std::string escaped_idl_string = idl_string; + replace_all_string(escaped_idl_string, "\"", "\\\""); + replace_all_string(escaped_idl_string, "#include", "\n#include"); + std::string cmd = "echo \"" + escaped_idl_string + "\" | " + context_->preprocessor_exec + " " + args; + context_->log(log::LogLevel::DEBUG, "PREPROCESS", + "Calling preprocessor '" + context_->preprocessor_exec + "' for an IDL string."); + return exec(cmd); + } + + std::string preprocess_file( + const std::string& idl_file) + { + std::vector includes; + std::string args = "-H "; + for (const std::string inc_path : context_->include_paths) + { + args += "-I " + inc_path + " "; + } + std::string cmd = context_->preprocessor_exec + " " + args + idl_file; + context_->log(log::LogLevel::DEBUG, "PREPROCESS", + "Calling preprocessor with command: " + cmd); + std::string output = exec(cmd); + return output; + } + std::shared_ptr build_on_ast( const std::shared_ptr& ast, std::shared_ptr scope = nullptr) From 8e586114ef0bf4cf7f1a7a90e6d93c8b9020d121 Mon Sep 17 00:00:00 2001 From: laura-eprosima Date: Tue, 22 Jun 2021 16:09:14 +0200 Subject: [PATCH 43/49] Print types with scope Signed-off-by: laura-eprosima --- tools/idl_validator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/idl_validator.cpp b/tools/idl_validator.cpp index e5b36826..5e081e13 100644 --- a/tools/idl_validator.cpp +++ b/tools/idl_validator.cpp @@ -22,6 +22,7 @@ int main( context.ignore_redefinition = true; context = idl::parse(idl_spec, context); std::cout << "Parse Success: " << std::boolalpha << context.success << std::endl; + for (auto [name, type] : context.get_all_scoped_types()) { if (type->kind() == TypeKind::STRUCTURE_TYPE) From 9b5737819cd2cfd1ffe606bb8c4da2397007277b Mon Sep 17 00:00:00 2001 From: laura-eprosima Date: Thu, 1 Jul 2021 10:09:24 +0200 Subject: [PATCH 44/49] Modify generator to return also the IDL separated by structures Signed-off-by: laura-eprosima --- include/xtypes/idl/generator.hpp | 18 +++- include/xtypes/idl/generator_deptree.hpp | 118 +++++++++++++++++++---- include/xtypes/idl/idl.hpp | 5 +- tools/idl_validator.cpp | 1 + 4 files changed, 115 insertions(+), 27 deletions(-) diff --git a/include/xtypes/idl/generator.hpp b/include/xtypes/idl/generator.hpp index acce02f2..2b39ad4f 100644 --- a/include/xtypes/idl/generator.hpp +++ b/include/xtypes/idl/generator.hpp @@ -133,7 +133,8 @@ inline std::string type_scope( inline std::string type_name( dependencytree::DependencyNode* node, - const DynamicType& type) + const DynamicType& type, + bool scoped) { static const std::map mapping = { @@ -196,7 +197,7 @@ inline std::string type_name( { size_t scope_end = type_name.rfind("::"); std::string scope = type_name.substr(0, scope_end); - if (node && (scope == node->module().scope())) // Redundant scope: get rid of it + if (node && (scope == node->module().scope()) && !scoped) // Redundant scope: get rid of it { ss << type_name.substr(scope_end + 2); } @@ -282,7 +283,8 @@ inline std::string structure( const std::string& name, const StructType& type, dependencytree::DependencyNode* struct_node, - size_t tabs) + size_t tabs, + std::map* struct_idl) { if (struct_node != nullptr) { @@ -307,7 +309,15 @@ inline std::string structure( } else { - ss << generator::type_name(struct_node, member.type()) << " " << member.name() << ";"; + if (member.type().kind() == TypeKind::STRUCTURE_TYPE && struct_idl != nullptr) + { + if (struct_idl->find(struct_node->type().name() + ":dependencies") != struct_idl->end()) + { + (*struct_idl)[struct_node->type().name() + ":dependencies"] += ","; + } + (*struct_idl)[struct_node->type().name() + ":dependencies"] += member.type().name(); + } + ss << generator::type_name(struct_node, member.type(), true) << " " << member.name() << ";"; } ss << std::endl; } diff --git a/include/xtypes/idl/generator_deptree.hpp b/include/xtypes/idl/generator_deptree.hpp index 931d0b93..b0e1b9b6 100644 --- a/include/xtypes/idl/generator_deptree.hpp +++ b/include/xtypes/idl/generator_deptree.hpp @@ -39,7 +39,8 @@ class DependencyModule; // "idl/generator.hpp" and forget about this file. inline std::string type_name( dependencytree::DependencyNode* node, - const DynamicType& type); + const DynamicType& type, + bool scoped = false); inline std::string aliase( const std::string& name, @@ -58,7 +59,8 @@ inline std::string structure( const std::string& name, const StructType& type, dependencytree::DependencyNode* struct_node = nullptr, - size_t tabs = 0); + size_t tabs = 0, + std::map* struct_idl = nullptr); inline std::string generate_union( const std::string& name, @@ -279,7 +281,8 @@ class DependencyNode /// \param[in] tabs Padding relative to module's scope. /// \return the generated sentence for this DependencyNode object. std::string generate_idl_sentence( - unsigned int tabs) + unsigned int tabs, + std::map* type_idl = nullptr) { using namespace generator; @@ -319,7 +322,7 @@ class DependencyNode } case ModuleElementKind::xSTRUCT: { - ss << structure(name(), static_cast(type()), this, tabs); + ss << structure(name(), static_cast(type()), this, tabs, type_idl); break; } case ModuleElementKind::xUNION: @@ -1004,11 +1007,12 @@ class DependencyModule /// \returns An string with the generated IDL sentence, if node belongs to this module. std::string generate_idl_sentence( DependencyNode& node, - unsigned int tabs) const + unsigned int tabs, + std::map* module_idl = nullptr) const { if (std::find(node_set_.begin(), node_set_.end(), node) != node_set_.end()) { - return node.generate_idl_sentence(tabs); + return node.generate_idl_sentence(tabs, module_idl); } else { @@ -1022,7 +1026,8 @@ class DependencyModule /// the "is_child" DependencyModule reference. /// \returns An string with the generated IDL. std::string generate_idl_module( - unsigned int tabs=0) + unsigned int tabs = 0, + std::map* struct_idl = nullptr) { std::stringstream ss; @@ -1033,7 +1038,7 @@ class DependencyModule for (const auto& ancestor : node.ancestors()) { std::stringstream ss_ancestor; - ss_ancestor << ancestor.get().generate_idl_sentence(tabs); + ss_ancestor << ancestor.get().generate_idl_sentence(tabs, struct_idl); if (ss_ancestor.rdbuf()->in_avail()) { @@ -1043,7 +1048,7 @@ class DependencyModule } std::stringstream ss_node; - ss_node << node.generate_idl_sentence(tabs); + ss_node << node.generate_idl_sentence(tabs, struct_idl); if (ss_node.rdbuf()->in_avail() && (!all_nodes_iterated() || (!d_inner_.empty() && !all_inner_iterated()))) @@ -1052,6 +1057,11 @@ class DependencyModule } ss << ss_node.str(); + + if (struct_idl != nullptr) + { + (*struct_idl)[node.type().name()] = ss_node.str(); + } } return ss.str(); @@ -1119,7 +1129,8 @@ class ModuleDependencyTree /// \returns A string representing IDL definition for the given module. std::string generate_idl( DependencyModule* dep_mod, - unsigned int tabs=0) const + unsigned int tabs=0, + std::map* module_idl = nullptr) const { if (dep_mod->iterated()) { @@ -1137,7 +1148,7 @@ class ModuleDependencyTree DependencyModule* p_ancestor = ancestor.lock().get(); if (!p_ancestor->iterated()) { - ss << generate_idl(p_ancestor, root ? 0 : tabs) << std::endl; + ss << generate_idl(p_ancestor, root ? 0 : tabs, module_idl) << std::endl; } } } @@ -1149,7 +1160,7 @@ class ModuleDependencyTree { if (onode.has_child_module(dep_mod)) { - ss << outer->generate_idl_sentence(onode, tabs); + ss << outer->generate_idl_sentence(onode, tabs, module_idl); if (!outer->all_nodes_iterated()) { @@ -1163,6 +1174,22 @@ class ModuleDependencyTree { ss << std::string(4 * tabs, ' ') << "module " << dep_mod->module().name() << std::endl; ss << std::string(4 * tabs, ' ') << "{" << std::endl; + + if (module_idl != nullptr) + { + if (module_idl->find(dep_mod->module().name() + ":DependencyModule") == module_idl->end() && !root) + { + if (dep_mod->has_outer() && module_idl->find(dep_mod->outer()->module().name() + ":DependencyModule") + != module_idl->end()) + { + (*module_idl)[dep_mod->outer()->module().name() + ":DependencyModule"] += ss.str(); + } + else + { + (*module_idl)[dep_mod->module().name() + ":DependencyModule"] = ss.str(); + } + } + } } for (auto& node : dep_mod->node_set()) @@ -1173,18 +1200,18 @@ class ModuleDependencyTree { if (!parent.lock().get()->iterated()) { - ss << generate_idl(parent.lock().get(), root ? 0 : tabs + 1) << std::endl; + ss << generate_idl(parent.lock().get(), root ? 0 : tabs + 1, module_idl) << std::endl; } } } } - ss << dep_mod->generate_idl_module(root ? 0 : tabs + 1); + ss << dep_mod->generate_idl_module(root ? 0 : tabs + 1, module_idl); // Iterate over inner DependencyModule list for (const auto& inner : dep_mod->inner()) { - ss << generate_idl(inner.get(), root ? 0 : tabs + 1); + ss << generate_idl(inner.get(), root ? 0 : tabs + 1, module_idl); if (!dep_mod->all_inner_iterated()) { @@ -1192,21 +1219,66 @@ class ModuleDependencyTree } } + if (module_idl != nullptr) + { + for (const auto& pair : *module_idl) + { + if (pair.first.find(":DependencyModule") == std::string::npos + && pair.first.find(":dependencies") == std::string::npos + && pair.first.find(dep_mod->module().name()) != std::string::npos) + { + std::string dep = ""; + + if (module_idl->find(dep_mod->module().name() + ":DependencyModule") != module_idl->end()) + { + dep = (*module_idl)[dep_mod->module().name() + ":DependencyModule"]; + } + + (*module_idl)[pair.first] = dep + pair.second; + } + } + } + if (!root) { ss << std::string(4 * tabs, ' ') << "};" << std::endl; + + if (module_idl != nullptr) + { + for (const auto& pair : *module_idl) + { + if (pair.first.find(":DependencyModule") == std::string::npos + && pair.first.find(":dependencies") == std::string::npos + && pair.first.find(dep_mod->module().name()) != std::string::npos) + { + if ((dep_mod->has_outer() && pair.first.find(dep_mod->outer()->module().name()) != std::string::npos) + || !dep_mod->has_outer()) + { + (*module_idl)[pair.first] = pair.second + std::string(4 * tabs, ' ') + "};\n"; + } + + } + } + } } dep_mod->set_iterated(true); + auto it = module_idl->find(dep_mod->module().name() + ":DependencyModule"); + if(it != module_idl->end()) + { + module_idl->erase(it); + } + return ss.str(); } /// \brief Helper method to generate IDL from root Module of this ModuleDependencyTree object. /// \returns A string representing IDL definition for root Module. - inline std::string generate_idl() const + inline std::string generate_idl( + std::map* module_idl = nullptr) const { - return generate_idl(dep_root_.get()); + return generate_idl(dep_root_.get(), 0, module_idl); } private: @@ -1217,9 +1289,11 @@ class ModuleDependencyTree /// \brief Helper function to generate an IDL from a Module. /// \param[in] module The Module whose IDL wants to be created. /// \returns An string containing IDL definition for the given Module. -inline std::string idl_from_module(const Module& module) +inline std::string idl_from_module( + const Module& module, + std::map* module_idl = nullptr) { - return ModuleDependencyTree(module).generate_idl(); + return ModuleDependencyTree(module).generate_idl(module_idl); } } //namespace dependencytree @@ -1228,9 +1302,11 @@ inline std::string idl_from_module(const Module& module) /// and abstracts the user about accessing dependencytree namespace. /// \param[in] module The module whose IDL wants to be created. /// \returns An string containing IDL definition for the given Module. -inline std::string module(const Module& module) +inline std::string module( + const Module& module, + std::map* module_idl = nullptr) { - return dependencytree::idl_from_module(module); + return dependencytree::idl_from_module(module, module_idl); } } //namespace generator } //namespace idl diff --git a/include/xtypes/idl/idl.hpp b/include/xtypes/idl/idl.hpp index b4bb2470..8c1a4629 100644 --- a/include/xtypes/idl/idl.hpp +++ b/include/xtypes/idl/idl.hpp @@ -90,9 +90,10 @@ inline std::string generate( /// \param[in] module Module to represent into IDL /// \return An IDL that represents the Module given. inline std::string generate( - const Module& module) + const Module& module, + std::map* module_idl = nullptr) { - return generator::module(module); + return generator::module(module, module_idl); } } //namespace idl diff --git a/tools/idl_validator.cpp b/tools/idl_validator.cpp index 5e081e13..e399aa8b 100644 --- a/tools/idl_validator.cpp +++ b/tools/idl_validator.cpp @@ -20,6 +20,7 @@ int main( context.log_level(idl::log::LogLevel::xDEBUG); context.print_log(true); context.ignore_redefinition = true; + context.allow_keyword_identifiers = true; context = idl::parse(idl_spec, context); std::cout << "Parse Success: " << std::boolalpha << context.success << std::endl; From f7be0a31e8a36c158e7ce88ee8b7f07c01b7162a Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 9 May 2023 08:40:59 +0200 Subject: [PATCH 45/49] update log traces Signed-off-by: Miguel Barro --- include/xtypes/idl/generator_deptree.hpp | 9 ++++++--- include/xtypes/idl/parser.hpp | 12 ++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/xtypes/idl/generator_deptree.hpp b/include/xtypes/idl/generator_deptree.hpp index b0e1b9b6..0e6f84d0 100644 --- a/include/xtypes/idl/generator_deptree.hpp +++ b/include/xtypes/idl/generator_deptree.hpp @@ -1264,10 +1264,13 @@ class ModuleDependencyTree dep_mod->set_iterated(true); - auto it = module_idl->find(dep_mod->module().name() + ":DependencyModule"); - if(it != module_idl->end()) + if (module_idl != nullptr) { - module_idl->erase(it); + auto it = module_idl->find(dep_mod->module().name() + ":DependencyModule"); + if(it != module_idl->end()) + { + module_idl->erase(it); + } } return ss.str(); diff --git a/include/xtypes/idl/parser.hpp b/include/xtypes/idl/parser.hpp index 6d7210f6..0d0796c5 100644 --- a/include/xtypes/idl/parser.hpp +++ b/include/xtypes/idl/parser.hpp @@ -686,7 +686,7 @@ class Parser if (ifs.fail()) { - context_->log(log::LogLevel::DEBUG, "FILE", + context_->log(log::xDEBUG, "FILE", "Cannot open file: " + std::string(path)); return false; } @@ -697,7 +697,7 @@ class Parser { ifs.seekg(0, std::ios::beg).read(&buff[0], static_cast(buff.size())); } - context_->log(log::LogLevel::DEBUG, "FILE", + context_->log(log::xDEBUG, "FILE", "Loaded file: " + std::string(path)); return true; } @@ -752,7 +752,7 @@ class Parser const std::string& idl_string) const { std::string args = "-H "; - for (const std::string inc_path : context_->include_paths) + for (const std::string& inc_path : context_->include_paths) { args += "-I " + inc_path + " "; } @@ -761,7 +761,7 @@ class Parser replace_all_string(escaped_idl_string, "\"", "\\\""); replace_all_string(escaped_idl_string, "#include", "\n#include"); std::string cmd = "echo \"" + escaped_idl_string + "\" | " + context_->preprocessor_exec + " " + args; - context_->log(log::LogLevel::DEBUG, "PREPROCESS", + context_->log(log::xDEBUG, "PREPROCESS", "Calling preprocessor '" + context_->preprocessor_exec + "' for an IDL string."); return exec(cmd); } @@ -771,12 +771,12 @@ class Parser { std::vector includes; std::string args = "-H "; - for (const std::string inc_path : context_->include_paths) + for (const std::string& inc_path : context_->include_paths) { args += "-I " + inc_path + " "; } std::string cmd = context_->preprocessor_exec + " " + args + idl_file; - context_->log(log::LogLevel::DEBUG, "PREPROCESS", + context_->log(log::xDEBUG, "PREPROCESS", "Calling preprocessor with command: " + cmd); std::string output = exec(cmd); return output; From 1d2dc382101ce2cdf0ce7cb441c6af0de340c003 Mon Sep 17 00:00:00 2001 From: laura-eprosima Date: Tue, 22 Jun 2021 16:09:14 +0200 Subject: [PATCH 46/49] Print types with scope Signed-off-by: laura-eprosima --- tools/idl_validator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/idl_validator.cpp b/tools/idl_validator.cpp index e399aa8b..e270c5de 100644 --- a/tools/idl_validator.cpp +++ b/tools/idl_validator.cpp @@ -19,6 +19,7 @@ int main( idl::Context context; context.log_level(idl::log::LogLevel::xDEBUG); context.print_log(true); + context.include_paths.push_back("/opt/ros/foxy/share/"); context.ignore_redefinition = true; context.allow_keyword_identifiers = true; context = idl::parse(idl_spec, context); From 49c936b24cf0b064ecebdc14e345b8b5f1eeae07 Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Fri, 12 May 2023 12:19:54 +0200 Subject: [PATCH 47/49] Fixing parser tool pin point issue Signed-off-by: Miguel Barro --- CMakeLists.txt | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 792b168d..2837cf55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,19 +134,8 @@ find_program(NODERED_EXECUTABLE NAMES node-red node-red@ PATH_SUFFIXES bin) if(XTYPES_BUILD_TOOLS OR NODERED_EXECUTABLE) compile_tool(xtypes_idl_validator SOURCE tools/idl_validator.cpp) - - # WSL for example lacks TMP - if(NOT ENV{TMP}) - set(TMP_ROOT "/tmp") - else() - set(TMP_ROOT "$ENV{TMP}") - endif() - - if (NODERED_EXECUTABLE) - file(WRITE ${TMP_ROOT}/idl_parser_path.txt "${PROJECT_BINARY_DIR}") - endif() - - unset(TMP_ROOT) + # allow node-red to locate it loading the overlay + install(TARGETS xtypes_idl_validator) endif() ##################################################################################### From dc74a6dd1090e640cb3c53bd4ee657f6bae328bb Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 30 May 2023 11:29:24 +0200 Subject: [PATCH 48/49] Making platform tool distro independent Signed-off-by: Miguel Barro --- tools/idl_validator.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/idl_validator.cpp b/tools/idl_validator.cpp index e270c5de..fb3a8c0f 100644 --- a/tools/idl_validator.cpp +++ b/tools/idl_validator.cpp @@ -1,6 +1,8 @@ #include #include +#include + using namespace eprosima::xtypes; int main( @@ -19,7 +21,19 @@ int main( idl::Context context; context.log_level(idl::log::LogLevel::xDEBUG); context.print_log(true); - context.include_paths.push_back("/opt/ros/foxy/share/"); + + // Introduce current ros2 paths + std::string distro(std::getenv("ROS_DISTRO")); + if (distro.empty()) + { + std::cout << "There is no ROS2 overlay loaded or ros_environment package is missing" << std::endl; + return -1; + } + else + { + context.include_paths.push_back("/opt/ros/" + distro + "/share/"); + } + context.ignore_redefinition = true; context.allow_keyword_identifiers = true; context = idl::parse(idl_spec, context); From f22f5002b4b7f87e89e00cb24a74f7aebc93ac0f Mon Sep 17 00:00:00 2001 From: Miguel Barro Date: Tue, 30 May 2023 16:01:01 +0200 Subject: [PATCH 49/49] Joakim Haugen's review Signed-off-by: Miguel Barro --- tools/idl_validator.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/idl_validator.cpp b/tools/idl_validator.cpp index fb3a8c0f..2ed5c566 100644 --- a/tools/idl_validator.cpp +++ b/tools/idl_validator.cpp @@ -23,15 +23,14 @@ int main( context.print_log(true); // Introduce current ros2 paths - std::string distro(std::getenv("ROS_DISTRO")); - if (distro.empty()) + const char * distro = std::getenv("ROS_DISTRO"); + if (nullptr == distro) { std::cout << "There is no ROS2 overlay loaded or ros_environment package is missing" << std::endl; - return -1; } else { - context.include_paths.push_back("/opt/ros/" + distro + "/share/"); + context.include_paths.push_back("/opt/ros/" + std::string(distro) + "/share/"); } context.ignore_redefinition = true;