From c0fc083c9de805e5825d7553507569febf6a6f93 Mon Sep 17 00:00:00 2001 From: Mindaugas Vinkelis Date: Mon, 23 Aug 2021 14:11:59 +0300 Subject: [PATCH] Additional improvements for v5.2.2 release * migration to github actions * additionally build tests/examples on windows and macos --- .github/workflows/on_linux.yml | 62 ++++++++++++++++++++++ .github/workflows/on_mac.yml | 26 ++++++++++ .github/workflows/on_windows.yml | 29 +++++++++++ .gitignore | 1 - CHANGELOG.md | 16 ++++++ CMakeLists.txt | 2 +- README.md | 29 +++++------ examples/composite_types.cpp | 14 +++-- include/bitsery/bitsery.h | 2 +- include/bitsery/ext/std_bitset.h | 4 +- include/bitsery/ext/std_optional.h | 17 +++++- scripts/show_coverage.sh | 0 tests/CMakeLists.txt | 66 ++++++++++++++---------- tests/brief_syntax.cpp | 8 ++- tests/serialization_context.cpp | 6 +-- tests/serialization_ext_std_optional.cpp | 8 ++- tests/serialization_ext_std_tuple.cpp | 14 +++-- tests/serialization_ext_std_variant.cpp | 8 ++- 18 files changed, 228 insertions(+), 84 deletions(-) create mode 100644 .github/workflows/on_linux.yml create mode 100644 .github/workflows/on_mac.yml create mode 100644 .github/workflows/on_windows.yml mode change 100755 => 100644 scripts/show_coverage.sh diff --git a/.github/workflows/on_linux.yml b/.github/workflows/on_linux.yml new file mode 100644 index 0000000..ea8a340 --- /dev/null +++ b/.github/workflows/on_linux.yml @@ -0,0 +1,62 @@ +name: On Linux + +on: + push: + branches: [ develop, master ] + pull_request: + branches: [ develop, master ] + +jobs: + build: + name: ${{ matrix.config.name }} + runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + config: + - name: "Ubuntu 18.04 with Clang 3.9" + cxx_ver: 11 + compiler: clang + compiler_ver: 3.9 + - name: "Ubuntu 18.04 with GCC 5.0" + cxx_ver: 11 + compiler: gcc + compiler_ver: 5 + - name: "Ubuntu 18.04 with GCC 11.0" + cxx_ver: 17 + compiler: gcc + compiler_ver: 11 + - name: "Ubuntu 18.04 with Clang 13" + cxx_ver: 17 + compiler: clang + compiler_ver: 13 + steps: + - name: Prepare specific Clang version + if: ${{ matrix.config.compiler == 'clang' }} + run: | + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo apt-add-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-13 main" + sudo apt update + sudo apt install clang-${{ matrix.config.compiler_ver}} + sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ matrix.config.compiler_ver}} 100 + sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ matrix.config.compiler_ver}} 100 + - name: Prepare specific GCC version + if: ${{ matrix.config.compiler == 'gcc' }} + run: | + sudo add-apt-repository ppa:ubuntu-toolchain-r/test + sudo apt update + sudo apt install g++-${{ matrix.config.compiler_ver}} + sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${{ matrix.config.compiler_ver}} 100 + sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${{ matrix.config.compiler_ver}} 100 + - name: Installing GTest + run: | + sudo add-apt-repository ppa:team-xbmc/ppa + sudo apt-get update + sudo apt-get install libgmock-dev + - uses: actions/checkout@v2 + - name: Configure + run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=${{ matrix.config.cxx_ver }} + - name: Build + run: cmake --build build + - name: Run tests + run: ctest --test-dir build/tests diff --git a/.github/workflows/on_mac.yml b/.github/workflows/on_mac.yml new file mode 100644 index 0000000..b929546 --- /dev/null +++ b/.github/workflows/on_mac.yml @@ -0,0 +1,26 @@ +name: On Mac +on: + push: + branches: [ develop, master ] + pull_request: + branches: [ develop, master ] + +jobs: + build: + name: macOS Latest + runs-on: macos-latest + steps: + - name: Installing GTest + run: | + git clone https://github.com/google/googletest.git + cd googletest + git checkout release-1.11.0 + cmake -S . -B build + cmake --build build --target install + - uses: actions/checkout@v2 + - name: Configure + run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17 + - name: Build + run: cmake --build build + - name: Run tests + run: ctest --test-dir build/tests diff --git a/.github/workflows/on_windows.yml b/.github/workflows/on_windows.yml new file mode 100644 index 0000000..7e91c86 --- /dev/null +++ b/.github/workflows/on_windows.yml @@ -0,0 +1,29 @@ +name: On Windows + +on: + push: + branches: [ develop, master ] + pull_request: + branches: [ develop, master ] + +jobs: + build: + name: Windows MSVC Latest + runs-on: windows-latest + steps: + - name: Installing GTest + run: | + git clone https://github.com/google/googletest.git + cd googletest + git checkout release-1.11.0 + cmake -S . -B build -Dgtest_force_shared_crt=ON + cmake --build build --config Release --target install + - uses: actions/checkout@v2 + - name: Configure + run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_FLAGS="/Zc:__cplusplus /permissive- /EHsc" + env: + CMAKE_PREFIX_PATH: "C:/Program Files (x86)/googletest-distribution/" + - name: Build + run: cmake --build build --config Release + - name: Run tests + run: ctest --test-dir build/tests diff --git a/.gitignore b/.gitignore index ba089c5..911d40c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ build/ cmake-build-* CTestConfig.cmake Testing/ -*.gch diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a0e732..4b1d836 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +# [5.2.2](https://github.com/fraillt/bitsery/compare/v5.2.1...v5.2.2) (2021-08-31) + +### Improvements +* add 16 byte value support #75 (thanks to [Victor Stewart](https://github.com/victorstewart)) +* avoid reinitializing nontrivial std::variant #77 (thanks to [Robbert van der Helm](https://github.com/robbert-vdh)) +* avoid reinitializing nontrivial std::optional. + +### Bug fixes +* fix missing headers for GCC11, also added test to check includes #82 (thanks to [michael-mueller-git](https://github.com/michael-mueller-git)) +* fixed **StdBitset** to build on macOS (proxy type, returned by `[]` operator wasn't correctly converted to unsigned integral type). + +### Other notes +* migrated to [Github actions](https://docs.github.com/en/actions) for running tests. +* fixes few warnings on MSVC compiler. +* now tests are also run on macOS and Windows. + # [5.2.1](https://github.com/fraillt/bitsery/compare/v5.2.0...v5.2.1) (2020-11-14) ### Improvements diff --git a/CMakeLists.txt b/CMakeLists.txt index 37e2bf1..5cdf03d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.1) project(bitsery LANGUAGES CXX - VERSION 5.2.1) + VERSION 5.2.2) #======== build options =================================== option(BITSERY_BUILD_EXAMPLES "Build examples" OFF) diff --git a/README.md b/README.md index 43b65ef..54a5c37 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Bitsery -[![Build Status](https://travis-ci.org/fraillt/bitsery.svg?branch=master)](https://travis-ci.org/fraillt/bitsery) +[![Build On Windows](https://github.com/fraillt/bitsery/actions/workflows/on_windows.yml/badge.svg)](https://github.com/fraillt/bitsery/actions/workflows/on_windows.yml) +[![Build On Mac](https://github.com/fraillt/bitsery/actions/workflows/on_mac.yml/badge.svg)](https://github.com/fraillt/bitsery/actions/workflows/on_mac.yml) +[![Build On Linux](https://github.com/fraillt/bitsery/actions/workflows/on_linux.yml/badge.svg)](https://github.com/fraillt/bitsery/actions/workflows/on_linux.yml) [![Join the chat at https://gitter.im/bitsery/Lobby](https://badges.gitter.im/bitsery/Lobby.svg)](https://gitter.im/bitsery/Lobby) Header only C++ binary serialization library. @@ -30,17 +32,17 @@ All cross-platform requirements are enforced at compile time, so serialized data Look at the numbers and features list, and decide yourself. -| library | data size | serialize | deserialize | -| ---------------- | --------- | --------- | ----------- | -| bitsery | 6913B | 959ms | 927ms | -| bitsery_compress | 4213B | 1282ms | 1115ms | -| boost | 11037B | 9826ms | 8313ms | -| cereal | 10413B | 6324ms | 5698ms | -| flatbuffers | 14924B | 5129ms | 2142ms | -| protobuf | 10018B | 11966ms | 13919ms | -| yas | 10463B | 1908ms | 1217ms | +| library | data size | ser time | des time | +| ----------- | --------- | -------- | -------- | +| bitsery | 6913B | 1119ms | 1166ms | +| boost | 11037B | 15391ms | 12912ms | +| cereal | 10413B | 10518ms | 10245ms | +| flatbuffers | 14924B | 9075ms | 3701ms | +| msgpack | 8857B | 3340ms | 13842ms | +| protobuf | 10018B | 21229ms | 22077ms | +| yas | 10463B | 2107ms | 1554ms | -*benchmarked on Ubuntu with GCC 8.3.0, more details can be found [here](https://github.com/fraillt/cpp_serializers_benchmark.git)* +*benchmarked on Ubuntu with GCC 10.3.0, more details can be found [here](https://github.com/fraillt/cpp_serializers_benchmark.git)* If still not convinced read more in library [motivation](doc/design/README.md) section. @@ -98,10 +100,7 @@ Works with C++11 compiler, no additional dependencies, include `{}, + bitsery::ext::OverloadValue{}, // it is not required to provide MyStruct overload, because it we have defined 'serialize' function for it }); }, @@ -66,7 +66,7 @@ void serialize(S& s, MyVariant& o) { // also note, that first parameter (serializer) is also "auto", this is required, so that it would be least specialized case // otherwise it will not compile if you any ext::Overload* helper defined, because it will have ambiguous definitions // (ext::OverLoad* defines (templated_type& s, concrete_type& o) and lambda would be (concrete_type& s, templated_type& o)) - [](auto& , auto& ) { + [](auto& , auto&) { assert(false); } }); @@ -81,8 +81,7 @@ using InputAdapter = bitsery::InputBufferAdapter; int main() { //set some random data - MyVariant data{MyTuple{-7549, {{-451, 2, 968, 75, 4, 156, 49}, 874.4f}}}; -// MyVariant data{MyStruct{{-451, 2, 968, 75, 4, 156, 49}, 874.4f}}; + MyVariant data{ MyTuple{-7549, {{-451, 2, 968, 75, 4, 156, 49}, 874.4f}} }; MyVariant res{}; //create buffer to store data @@ -94,19 +93,18 @@ int main() { //same as serialization, but returns deserialization state as a pair //first = error code, second = is buffer was successfully read from begin to the end. - auto state = bitsery::quickDeserialization({buffer.begin(), writtenSize}, res); + auto state = bitsery::quickDeserialization({ buffer.begin(), writtenSize }, res); assert(state.first == bitsery::ReaderError::NoError && state.second); assert(data == res); } #else #if defined(_MSC_VER) -#pragma message("example works only on c++17") +#pragma message("C++17 and /Zc:__cplusplus option is required to enable this example") #else -#warning "example works only on c++17" +#pragma message("C++17 is required to enable this example") #endif int main() { return 0; } - #endif \ No newline at end of file diff --git a/include/bitsery/bitsery.h b/include/bitsery/bitsery.h index 79823ff..391804f 100644 --- a/include/bitsery/bitsery.h +++ b/include/bitsery/bitsery.h @@ -26,7 +26,7 @@ #define BITSERY_MAJOR_VERSION 5 #define BITSERY_MINOR_VERSION 2 -#define BITSERY_PATCH_VERSION 1 +#define BITSERY_PATCH_VERSION 2 #define BITSERY_QUOTE_MACRO(name) #name #define BITSERY_BUILD_VERSION_STR(major,minor, patch) \ diff --git a/include/bitsery/ext/std_bitset.h b/include/bitsery/ext/std_bitset.h index 6b83946..b2a6b9e 100644 --- a/include/bitsery/ext/std_bitset.h +++ b/include/bitsery/ext/std_bitset.h @@ -103,7 +103,7 @@ namespace bitsery { template void serializeLeftoverImpl(Writer& w, const std::bitset &obj, size_t from, size_t to, std::integral_constant) const { for (auto i = from; i < to; ++i) { - w.writeBits(obj[i], 1); + w.writeBits(obj[i] ? 1u : 0u, 1); } } @@ -126,7 +126,7 @@ namespace bitsery { for (auto i = from; i < to; ++i) { uint8_t res = 0u; r.readBits(res, 1); - obj[i] = res; + obj[i] = res == 1; } } diff --git a/include/bitsery/ext/std_optional.h b/include/bitsery/ext/std_optional.h index ad0a708..57ec9d1 100644 --- a/include/bitsery/ext/std_optional.h +++ b/include/bitsery/ext/std_optional.h @@ -56,13 +56,26 @@ namespace bitsery { if (_alignBeforeData) des.adapter().align(); if (exists) { - obj = ::bitsery::Access::create(); - fnc(des, *obj); + deserialize_impl(des, obj, fnc, std::is_trivial{}); } else { obj = std::nullopt; } } private: + + template + void deserialize_impl(Des &des, std::optional &obj, Fnc &&fnc, std::true_type) const { + obj = ::bitsery::Access::create(); + fnc(des, *obj); + } + + template + void deserialize_impl(Des &des, std::optional &obj, Fnc &&fnc, std::false_type) const { + if (!obj) { + obj = ::bitsery::Access::create(); + } + fnc(des, *obj); + } bool _alignBeforeData; }; } diff --git a/scripts/show_coverage.sh b/scripts/show_coverage.sh old mode 100755 new mode 100644 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c721d9c..a3ee631 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,8 +20,9 @@ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #SOFTWARE. -cmake_minimum_required(VERSION 3.10) -project(bitsery_tests CXX) +cmake_minimum_required(VERSION 3.11) +project(bitsery_tests + LANGUAGES CXX) find_package(GTest 1.10 REQUIRED) @@ -62,31 +63,40 @@ if (ParentDir) # add headers so IDE correctly show them target_sources(bitsery.dummy_for_ide PRIVATE ${HeadersForIDE} serialization_test_utils.h) target_link_libraries(bitsery.dummy_for_ide PRIVATE GTest::Main Bitsery::bitsery) + + # creates a "check_includes" target to verify if all headers has required includes + # to simplify things a little bit, it only works with modern compiler (C++17) + # as some bitsery extensions require C++17 compliant compiler. + if("cxx_std_17" IN_LIST CMAKE_CXX_COMPILE_FEATURES) + add_library(check_includes OBJECT) + target_compile_features(check_includes PRIVATE cxx_std_17) + file(WRITE ${CMAKE_BINARY_DIR}/check_includes.in " +// generated by CMake to verify header includes. +// we need exactly 201703L, because some compilers with experimental C++17 support +// provides bigger number than 201402L (C++14) but doesn't actually has enough +// functionality to build these files +#if __cplusplus >= 201703L + #include \"@HeaderFile@\" +#elif defined(_MSC_VER) +#pragma message(\"/Zc:__cplusplus option is required to enable check_includes\") +#else +#define XSTR(x) STR(x) +#define STR(x) #x +#pragma message (\"`__cplusplus` macro value should be 201703L or greater, actual value is: \" XSTR(__cplusplus)) +#endif +") + + file(GLOB_RECURSE HeaderFiles "${ParentDir}/include/bitsery/*.h") + foreach (HeaderFile ${HeaderFiles}) + SET(CHK_TARGET_NAME "chk_inc_${HeaderFile}") + STRING(REPLACE "${ParentDir}/include/bitsery/" "" CHK_TARGET_NAME ${CHK_TARGET_NAME}) + STRING(REGEX REPLACE "/" "_" CHK_TARGET_NAME ${CHK_TARGET_NAME}) + STRING(REGEX REPLACE "\\\\" "_" CHK_TARGET_NAME ${CHK_TARGET_NAME}) + configure_file(${CMAKE_BINARY_DIR}/check_includes.in "${CHK_TARGET_NAME}.cpp") + target_sources(check_includes PRIVATE "${CHK_TARGET_NAME}.cpp") + endforeach () + else() + message(WARNING "`check_includes` target will be disabled, as it require compiler with C++17 support.") + endif() endif() -# Check missing includes for each header file in include/bitsery -# We compile each header files individually to check if each header contains all required includes -# Code adopted from `https://stackoverflow.com/questions/57885042` -# Usage: -# run from repo root directory -# > mkdir -p build && cd build -# > cmake -D BITSERY_BUILD_TESTS=1 .. -# > make check_includes -add_custom_target(check_includes) -get_directory_property(ParentDir PARENT_DIRECTORY) -if (ParentDir) - message("add header include test, run test with 'make check_includes'") - file(GLOB_RECURSE HeaderFiles "${ParentDir}/include/bitsery/*.h") - FOREACH (HeaderFile ${HeaderFiles}) - SET(CHK_TARGET_NAME "${HeaderFile}.chk") - STRING(REPLACE "${ParentDir}/include/bitsery/" "" CHK_TARGET_NAME ${CHK_TARGET_NAME}) - STRING(REGEX REPLACE "/" "_" CHK_TARGET_NAME ${CHK_TARGET_NAME}) - STRING(REGEX REPLACE "\\\\" "_" CHK_TARGET_NAME ${CHK_TARGET_NAME}) - add_custom_target( - ${CHK_TARGET_NAME} - COMMAND ${CMAKE_CXX_COMPILER} -c ${HeaderFile} - VERBATIM - ) - add_dependencies(check_includes ${CHK_TARGET_NAME}) - ENDFOREACH () -endif() diff --git a/tests/brief_syntax.cpp b/tests/brief_syntax.cpp index 64ac347..d564641 100644 --- a/tests/brief_syntax.cpp +++ b/tests/brief_syntax.cpp @@ -39,12 +39,10 @@ #if __cplusplus > 201402L #include #include +#elif defined(_MSC_VER) +#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::tuple and std::variant brief syntax tests") #else -/*#if defined(_MSC_VER) -#pragma message("tuple and variant only works with c++17") -#else -#warning "tuple and variant only works with c++17" -#endif*/ +#pragma message("C++17 is required to enable std::tuple and std::variant brief syntax tests") #endif #include diff --git a/tests/serialization_context.cpp b/tests/serialization_context.cpp index 0cca083..22fffd9 100644 --- a/tests/serialization_context.cpp +++ b/tests/serialization_context.cpp @@ -41,7 +41,7 @@ TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext) { TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements) { - MultipleTypesContext ctx{5, 798.654, 'F'}; + MultipleTypesContext ctx{5, 798.654f, 'F'}; BasicSerializationContext c1; auto& ser1 = c1.createSerializer(ctx); @@ -59,7 +59,7 @@ TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull) *ser.contextOrNull() = 2; EXPECT_THAT(ctx1, Eq(2)); - MultipleTypesContext ctx2{5, 798.654, 'F'}; + MultipleTypesContext ctx2{5, 798.654f, 'F'}; BasicSerializationContext c2; auto& des = c2.createDeserializer(ctx2); EXPECT_THAT(des.contextOrNull(), ::testing::IsNull()); @@ -105,4 +105,4 @@ TEST(SerializationContext, WhenMultipleConvertibleTypesExistsThenFirstMatchIsTak //Base will not be accessable in this case, because Derived is first valid match EXPECT_THAT(des.context().value, Eq(std::get<1>(ctx2).value)); } -} \ No newline at end of file +} diff --git a/tests/serialization_ext_std_optional.cpp b/tests/serialization_ext_std_optional.cpp index c3d1a8a..b07dc60 100644 --- a/tests/serialization_ext_std_optional.cpp +++ b/tests/serialization_ext_std_optional.cpp @@ -120,10 +120,8 @@ TEST(SerializeExtensionStdOptional, NoAlignAfterStateWriteRead) { EXPECT_THAT(t1.value(), Eq(r1.value())); } +#elif defined(_MSC_VER) +#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::optional tests") #else -/*#if defined(_MSC_VER) -#pragma message("Tests for StdOptional requires C++17") -#else -#warning "Tests for StdOptional requires C++17" -#endif*/ +#pragma message("C++17 is required to enable std::optional tests") #endif diff --git a/tests/serialization_ext_std_tuple.cpp b/tests/serialization_ext_std_tuple.cpp index 1d7f95d..16f4034 100644 --- a/tests/serialization_ext_std_tuple.cpp +++ b/tests/serialization_ext_std_tuple.cpp @@ -102,8 +102,8 @@ private: }; TEST(SerializeExtensionStdTuple, NonDefaultConstructable) { - std::tuple t1{34}; - std::tuple r1{8}; + std::tuple t1{34.0f}; + std::tuple r1{8.0f}; SerializationContext ctx; ctx.createSerializer().ext(t1, bitsery::ext::StdTuple{ [](auto& s, NonDefaultConstructable& v) { @@ -118,10 +118,8 @@ TEST(SerializeExtensionStdTuple, NonDefaultConstructable) { EXPECT_THAT(t1, Eq(r1)); } +#elif defined(_MSC_VER) +#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::tuple tests") #else -/*#if defined(_MSC_VER) -#pragma message("Tests for StdTuple requires C++17") -#else -#warning "Tests for StdTuple requires C++17" -#endif*/ -#endif \ No newline at end of file +#pragma message("C++17 is required to enable std::tuple tests") +#endif diff --git a/tests/serialization_ext_std_variant.cpp b/tests/serialization_ext_std_variant.cpp index 160b134..bbccc10 100644 --- a/tests/serialization_ext_std_variant.cpp +++ b/tests/serialization_ext_std_variant.cpp @@ -167,10 +167,8 @@ TEST(SerializeExtensionStdVariant, CorrectlyHandleMonoState) { } +#elif defined(_MSC_VER) +#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::variant tests") #else -/*#if defined(_MSC_VER) -#pragma message("Tests for StdVariant requires C++17") -#else -#warning "Tests for StdVariant requires C++17" -#endif*/ +#pragma message("C++17 is required to enable std::variant tests") #endif