├── cmake ├── sul-dynamic_bitset-config.cmake └── flags.cmake ├── docs ├── custom.css ├── CMakeLists.txt └── header.html ├── .gitignore ├── ide ├── configure_VS2017_v141_default.cmd ├── configure_VS2019_v142_default.cmd ├── configure_VS2022_v143_default.cmd ├── configure_VS2017_v141_x64.cmd ├── configure_VS2017_v141_Win32.cmd ├── configure_VS2019_v142_x64.cmd ├── configure_VS2022_v143_x64.cmd ├── configure_VS2019_v142_Win32.cmd └── configure_VS2022_v143_Win32.cmd ├── .gitmodules ├── tests ├── include │ ├── config.hpp │ ├── utils.hpp │ ├── RandomBitsetStringGenerator.hpp │ ├── MultiTakeGenerator.hpp │ ├── RandomChunkGenerator.hpp │ └── RandomDynamicBitsetGenerator.hpp ├── src │ ├── count.cpp │ ├── find_first_find_next.cpp │ └── tests.cpp └── CMakeLists.txt ├── LICENSE ├── .clang-format ├── example ├── CMakeLists.txt └── src │ └── main.cpp ├── .github ├── workflows │ ├── documentation.yml │ ├── macos.yml │ ├── windows-msvc.yml │ ├── coverage.yml │ ├── windows-msys2.yml │ └── ubuntu.yml └── actions │ ├── setup_doxygen │ └── action.yml │ ├── setup_cmake │ └── action.yml │ └── setup_ccache │ └── action.yml ├── README.md └── CMakeLists.txt /cmake/sul-dynamic_bitset-config.cmake: -------------------------------------------------------------------------------- 1 | include(${CMAKE_CURRENT_LIST_DIR}/sul-dynamic_bitset.cmake) -------------------------------------------------------------------------------- /docs/custom.css: -------------------------------------------------------------------------------- 1 | html { 2 | --content-maxwidth: auto; 3 | --top-height: 150px; 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ######################## 2 | ## Clion 3 | ######################## 4 | 5 | .idea/ 6 | cmake-build-*/ 7 | 8 | ######################## 9 | ## Visual Studio 10 | ######################## 11 | 12 | ide/VS*/ 13 | -------------------------------------------------------------------------------- /ide/configure_VS2017_v141_default.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 15 2017" 3 | set TOOLSET=v141 4 | set CFGS=Debug;RelWithDebInfo;Release 5 | set OUT=VS2017_%TOOLSET%_default 6 | mkdir %OUT% 2>NUL 7 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 8 | -------------------------------------------------------------------------------- /ide/configure_VS2019_v142_default.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 16 2019" 3 | set TOOLSET=v142 4 | set CFGS=Debug;RelWithDebInfo;Release;Sanitize 5 | set OUT=VS2019_%TOOLSET%_default 6 | mkdir %OUT% 2>NUL 7 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 8 | -------------------------------------------------------------------------------- /ide/configure_VS2022_v143_default.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 17 2022" 3 | set TOOLSET=v143 4 | set CFGS=Debug;RelWithDebInfo;Release;Sanitize 5 | set OUT=VS2022_%TOOLSET%_default 6 | mkdir %OUT% 2>NUL 7 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 8 | -------------------------------------------------------------------------------- /ide/configure_VS2017_v141_x64.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 15 2017" 3 | set TOOLSET=v141 4 | set ARCH=x64 5 | set CFGS=Debug;RelWithDebInfo;Release 6 | set OUT=VS2017_%TOOLSET%_%ARCH% 7 | mkdir %OUT% 2>NUL 8 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -A %ARCH% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 9 | -------------------------------------------------------------------------------- /ide/configure_VS2017_v141_Win32.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 15 2017" 3 | set TOOLSET=v141 4 | set ARCH=Win32 5 | set CFGS=Debug;RelWithDebInfo;Release 6 | set OUT=VS2017_%TOOLSET%_%ARCH% 7 | mkdir %OUT% 2>NUL 8 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -A %ARCH% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 9 | -------------------------------------------------------------------------------- /ide/configure_VS2019_v142_x64.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 16 2019" 3 | set TOOLSET=v142 4 | set ARCH=x64 5 | set CFGS=Debug;RelWithDebInfo;Release;Sanitize 6 | set OUT=VS2019_%TOOLSET%_%ARCH% 7 | mkdir %OUT% 2>NUL 8 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -A %ARCH% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 9 | -------------------------------------------------------------------------------- /ide/configure_VS2022_v143_x64.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 17 2022" 3 | set TOOLSET=v143 4 | set ARCH=x64 5 | set CFGS=Debug;RelWithDebInfo;Release;Sanitize 6 | set OUT=VS2022_%TOOLSET%_%ARCH% 7 | mkdir %OUT% 2>NUL 8 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -A %ARCH% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 9 | -------------------------------------------------------------------------------- /ide/configure_VS2019_v142_Win32.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 16 2019" 3 | set TOOLSET=v142 4 | set ARCH=Win32 5 | set CFGS=Debug;RelWithDebInfo;Release;Sanitize 6 | set OUT=VS2019_%TOOLSET%_%ARCH% 7 | mkdir %OUT% 2>NUL 8 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -A %ARCH% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 9 | -------------------------------------------------------------------------------- /ide/configure_VS2022_v143_Win32.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set TARGET="Visual Studio 17 2022" 3 | set TOOLSET=v143 4 | set ARCH=Win32 5 | set CFGS=Debug;RelWithDebInfo;Release;Sanitize 6 | set OUT=VS2022_%TOOLSET%_%ARCH% 7 | mkdir %OUT% 2>NUL 8 | cmd /C "pushd %OUT% & cmake ../.. -G %TARGET% -T %TOOLSET% -A %ARCH% -DCMAKE_CONFIGURATION_TYPES=%CFGS%" 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "extlibs/Catch2"] 2 | path = extlibs/Catch2 3 | url = https://github.com/catchorg/Catch2 4 | [submodule "extlibs/libpopcnt"] 5 | path = extlibs/libpopcnt 6 | url = https://github.com/kimwalisch/libpopcnt 7 | [submodule "docs/doxygen-awesome-css"] 8 | path = docs/doxygen-awesome-css 9 | url = https://github.com/jothepro/doxygen-awesome-css 10 | -------------------------------------------------------------------------------- /tests/include/config.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #ifndef DYNAMIC_BITSET_CONFIG_HPP 9 | #define DYNAMIC_BITSET_CONFIG_HPP 10 | 11 | constexpr size_t RANDOM_VECTORS_TO_TEST = 100; 12 | constexpr size_t RANDOM_VARIATIONS_TO_TEST = 10; 13 | 14 | #endif // DYNAMIC_BITSET_CONFIG_HPP 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Maxime Pinard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignArrayOfStructures: Left 5 | AlignEscapedNewlines: DontAlign 6 | AlignTrailingComments: 7 | Kind: Never 8 | AllowShortEnumsOnASingleLine: false 9 | AllowShortFunctionsOnASingleLine: None 10 | AlwaysBreakTemplateDeclarations: Yes 11 | BinPackArguments: false 12 | BinPackParameters: false 13 | BreakBeforeBinaryOperators: NonAssignment 14 | BreakBeforeBraces: Allman 15 | BreakConstructorInitializers: BeforeComma 16 | BreakInheritanceList: BeforeComma 17 | ColumnLimit: 120 18 | ContinuationIndentWidth: 2 19 | IndentCaseBlocks: true 20 | IndentCaseLabels: true 21 | IndentPPDirectives: AfterHash 22 | IndentWidth: 4 23 | InsertNewlineAtEOF: true 24 | NamespaceIndentation: All 25 | PackConstructorInitializers: CurrentLine 26 | PointerAlignment: Left 27 | #ReflowComments: false # for Doxygen 28 | SeparateDefinitionBlocks: Always 29 | ShortNamespaceLines: 0 30 | SpaceAfterTemplateKeyword: false 31 | SpaceBeforeParens: Custom 32 | SpaceBeforeParensOptions: 33 | AfterControlStatements: false 34 | AfterForeachMacros: false 35 | AfterIfMacros: false 36 | #AfterPlacementOperator: false 37 | SpaceBeforeRangeBasedForLoopColon: false 38 | TabWidth: 4 39 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Check dynamic_bitset 2 | if(NOT TARGET dynamic_bitset) 3 | message(FATAL_ERROR "dynamic_bitset target required for the example") 4 | endif() 5 | 6 | # Declare dynamic_bitset_example 7 | add_executable(dynamic_bitset_example) 8 | set_target_properties(dynamic_bitset_example PROPERTIES FOLDER "dynamic_bitset") 9 | 10 | # Add sources 11 | target_sources(dynamic_bitset_example PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp") 12 | source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp") 13 | 14 | # Link dynamic_bitset 15 | target_link_libraries(dynamic_bitset_example PRIVATE sul::dynamic_bitset) 16 | 17 | # Require C++17/20 18 | if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES) 19 | target_compile_features(dynamic_bitset_example PRIVATE cxx_std_20) 20 | else() 21 | target_compile_features(dynamic_bitset_example PRIVATE cxx_std_17) 22 | endif() 23 | 24 | # Generate format target? 25 | if(DYNAMICBITSET_FORMAT_TARGET) 26 | add_custom_target( 27 | format-dynamic_bitset_example 28 | COMMAND "${CLANG_FORMAT}" -style=file -i "${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp" 29 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 30 | VERBATIM 31 | ) 32 | set_target_properties(format-dynamic_bitset_example PROPERTIES FOLDER "dynamic_bitset/format") 33 | endif() 34 | -------------------------------------------------------------------------------- /tests/include/utils.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #ifndef DYNAMIC_BITSET_UTILS_HPP 9 | #define DYNAMIC_BITSET_UTILS_HPP 10 | 11 | #include 12 | 13 | #include 14 | 15 | template 16 | constexpr size_t bits_number = std::numeric_limits::digits; 17 | 18 | template 19 | static constexpr T zero_block = T(0); 20 | 21 | template 22 | static constexpr T one_block = T(~zero_block); 23 | 24 | template 25 | constexpr bool bit_value(T value, size_t bit_pos) noexcept 26 | { 27 | static_assert(std::is_unsigned::value, "T is not an unsigned integral type"); 28 | assert(bit_pos < bits_number); 29 | return (value & (T(1) << bit_pos)) != T(0); 30 | } 31 | 32 | template 33 | constexpr bool check_unused_bits(const sul::dynamic_bitset& bitset) noexcept 34 | { 35 | const size_t extra_bits = bitset.size() % sul::dynamic_bitset::bits_per_block; 36 | if(extra_bits > 0) 37 | { 38 | assert(bitset.data() != nullptr); 39 | assert(bitset.num_blocks() > 0); 40 | return (*(bitset.data() + bitset.num_blocks() - 1) & (one_block << extra_bits)) == zero_block; 41 | } 42 | return true; 43 | } 44 | 45 | template 46 | constexpr bool check_size(const sul::dynamic_bitset& bitset) noexcept 47 | { 48 | const size_t blocks_required = bitset.size() / sul::dynamic_bitset::bits_per_block 49 | + static_cast(bitset.size() % sul::dynamic_bitset::bits_per_block > 0); 50 | return blocks_required == bitset.num_blocks(); 51 | } 52 | 53 | template 54 | constexpr bool check_consistency(const sul::dynamic_bitset& bitset) noexcept 55 | { 56 | return check_unused_bits(bitset) && check_size(bitset); 57 | } 58 | 59 | #endif // DYNAMIC_BITSET_UTILS_HPP 60 | -------------------------------------------------------------------------------- /tests/src/count.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #include "RandomDynamicBitsetGenerator.hpp" 9 | #include "config.hpp" 10 | #include "utils.hpp" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #if DYNAMIC_BITSET_CAN_USE_LIBPOPCNT 22 | # define COUNT_TESTED_IMPL "libpopcnt" 23 | #elif DYNAMIC_BITSET_CAN_USE_STD_BITOPS 24 | # define COUNT_TESTED_IMPL "C++20 binary operations" 25 | #elif DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN 26 | # define COUNT_TESTED_IMPL "gcc builtins" 27 | #elif DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_POPCOUNT 28 | # define COUNT_TESTED_IMPL "clang builtins" 29 | #else 30 | # define COUNT_TESTED_IMPL "base" 31 | #endif 32 | 33 | TEMPLATE_TEST_CASE( 34 | "count (" COUNT_TESTED_IMPL ")", "[dynamic_bitset][libpopcnt][builtin][c++20]", uint16_t, uint32_t, uint64_t) 35 | { 36 | SECTION("empty bitset") 37 | { 38 | sul::dynamic_bitset bitset; 39 | 40 | REQUIRE(bitset.count() == 0); 41 | } 42 | 43 | SECTION("non-empty bitset") 44 | { 45 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 46 | CAPTURE(bitset); 47 | 48 | size_t count = 0; 49 | for(size_t i = 0; i < bitset.size(); ++i) 50 | { 51 | count += static_cast(bitset[i]); 52 | } 53 | 54 | SECTION("general") 55 | { 56 | REQUIRE(bitset.count() == count); 57 | } 58 | 59 | SECTION("first block empty") 60 | { 61 | bitset.append(0); 62 | bitset <<= bits_number; 63 | REQUIRE(bitset.count() == count); 64 | } 65 | 66 | SECTION("last block empty") 67 | { 68 | bitset.append(0); 69 | REQUIRE(bitset.count() == count); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | env: 9 | CMAKE_VERSION: 3.30.3 10 | DOXYGEN_VERSION: 1.12.0 11 | DOXYGEN_LIBCLANG_VERSION: 18 12 | 13 | jobs: 14 | build: 15 | name: ubuntu-24.04 - documentation 16 | runs-on: ubuntu-24.04 17 | steps: 18 | - name: Checkout dynamic_bitset 19 | uses: actions/checkout@v4 20 | with: 21 | submodules: recursive 22 | path: dynamic_bitset 23 | 24 | - name: Setup CMake 25 | id: cmake 26 | uses: ./dynamic_bitset/.github/actions/setup_cmake 27 | with: 28 | cmake_version: ${{env.CMAKE_VERSION}} 29 | used_env: ubuntu-24.04 30 | 31 | - name: Setup Doxygen 32 | id: doxygen 33 | uses: ./dynamic_bitset/.github/actions/setup_doxygen 34 | with: 35 | doxygen_version: ${{env.DOXYGEN_VERSION}} 36 | doxygen_libclang_version: ${{env.DOXYGEN_LIBCLANG_VERSION}} 37 | used_env: ubuntu-24.04 38 | 39 | - name: CMake version 40 | run: ${{steps.cmake.outputs.cmake_binary}} --version 41 | 42 | - name: Configure 43 | run: >- 44 | ${{steps.cmake.outputs.cmake_binary}} 45 | -S "${{github.workspace}}/dynamic_bitset" 46 | -B "${{github.workspace}}/dynamic_bitset/build" 47 | -D Doxygen_ROOT=${{steps.doxygen.outputs.doxygen_install}} 48 | -D CMAKE_POLICY_DEFAULT_CMP0074=NEW 49 | 50 | - name: Build 51 | run: >- 52 | ${{steps.cmake.outputs.cmake_binary}} 53 | --build "${{github.workspace}}/dynamic_bitset/build" 54 | --target dynamic_bitset_docs 55 | 56 | - name: Deploy 57 | id: deploy 58 | run: | 59 | set -eu 60 | mkdir tmp-git 61 | cd tmp-git 62 | git init 63 | git config user.name "${GITHUB_ACTOR}" 64 | git config user.email "${GITHUB_ACTOR}@bots.github.com" 65 | git remote add origin "https://x-access-token:${{secrets.GITHUB_TOKEN}}@github.com/${GITHUB_REPOSITORY}.git" 66 | git fetch origin 67 | git checkout -t origin/gh-pages 68 | rm -rf ./* 69 | cp -r "${{github.workspace}}/dynamic_bitset/build/docs/html/." . 70 | git add -A . 71 | if git commit -m "Update"; then 72 | git push 73 | echo "documentation updated" 74 | else 75 | echo "no changes to commit" 76 | fi 77 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Check dynamic_bitset 2 | if(NOT TARGET dynamic_bitset) 3 | message(FATAL_ERROR "dynamic_bitset target required for the docs") 4 | endif() 5 | 6 | # doxygen-awesome-css 7 | get_filename_component(DOXYGEN_AWESOME_CSS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/doxygen-awesome-css" ABSOLUTE) 8 | if(NOT EXISTS "${DOXYGEN_AWESOME_CSS_PATH}/README.md") 9 | message(FATAL_ERROR "doxygen-awesome-css dependency is missing, maybe you didn't pull the git submodules") 10 | endif() 11 | 12 | # Find Doxygen 13 | find_package(Doxygen QUIET) 14 | if(DOXYGEN_FOUND) 15 | message(STATUS "Doxygen ${DOXYGEN_VERSION} found") 16 | else() 17 | message(WARNING "Doxygen not found, dynamic_bitset_docs target not generated") 18 | return() 19 | endif() 20 | 21 | # Configure Doxygen 22 | set(DOXYGEN_GENERATE_TREEVIEW YES) 23 | set(DOXYGEN_DISABLE_INDEX NO) 24 | set(DOXYGEN_FULL_SIDEBAR NO) 25 | set(DOXYGEN_GENERATE_HTML YES) 26 | set(DOXYGEN_GENERATE_LATEX NO) 27 | set(DOXYGEN_GENERATE_XML NO) 28 | set(DOXYGEN_FULL_PATH_NAMES YES) 29 | set(DOXYGEN_STRIP_FROM_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../include") 30 | set(DOXYGEN_STRIP_FROM_INC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../include") 31 | set(DOXYGEN_EXCLUDE_SYMBOLS "DYNAMIC_BITSET_CAN_USE_*") 32 | set(DOXYGEN_ALIASES "\"complexity=@par Complexity^^\"") 33 | set(DOXYGEN_OUTPUT_LANGUAGE "English") 34 | set(DOXYGEN_MARKDOWN_SUPPORT YES) 35 | set(DOXYGEN_HTML_COLORSTYLE LIGHT) 36 | set(DOXYGEN_HTML_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/header.html") 37 | set(DOXYGEN_HTML_EXTRA_FILES 38 | "${DOXYGEN_AWESOME_CSS_PATH}/doxygen-awesome-darkmode-toggle.js" 39 | "${DOXYGEN_AWESOME_CSS_PATH}/doxygen-awesome-fragment-copy-button.js" 40 | "${DOXYGEN_AWESOME_CSS_PATH}/doxygen-awesome-paragraph-link.js" 41 | ) 42 | set(DOXYGEN_HTML_EXTRA_STYLESHEET 43 | "${DOXYGEN_AWESOME_CSS_PATH}/doxygen-awesome.css" 44 | "${DOXYGEN_AWESOME_CSS_PATH}/doxygen-awesome-sidebar-only.css" 45 | "${DOXYGEN_AWESOME_CSS_PATH}/doxygen-awesome-sidebar-only-darkmode-toggle.css" 46 | "${CMAKE_CURRENT_SOURCE_DIR}/custom.css" 47 | ) 48 | 49 | # Set files and generate target 50 | set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md) 51 | doxygen_add_docs(dynamic_bitset_docs 52 | "${CMAKE_CURRENT_SOURCE_DIR}/../include/sul/dynamic_bitset.hpp" 53 | "${CMAKE_CURRENT_SOURCE_DIR}/../README.md" 54 | COMMENT "Generate dynamic_bitset docs" 55 | ) 56 | 57 | # Set target IDE folder 58 | set_target_properties(dynamic_bitset_docs PROPERTIES FOLDER "dynamic_bitset") 59 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: macOS 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | env: 8 | CMAKE_VERSION: 3.30.3 9 | 10 | jobs: 11 | build: 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | config: [ 16 | # {os: macos-13, xcode: 14.1}, 17 | # {os: macos-13, xcode: 14.2}, 18 | {os: macos-13, xcode: 14.3.1}, 19 | # {os: macos-13, xcode: 15.0.1}, 20 | # {os: macos-13, xcode: 15.1}, 21 | {os: macos-13, xcode: 15.2}, 22 | # {os: macos-14, xcode: 14.3.1}, 23 | # {os: macos-14, xcode: 15.0.1}, 24 | # {os: macos-14, xcode: 15.1}, 25 | # {os: macos-14, xcode: 15.2}, 26 | # {os: macos-14, xcode: 15.3}, 27 | {os: macos-14, xcode: 15.4}, 28 | ] 29 | build_type: [Debug, Release, Sanitize] 30 | name: ${{matrix.config.os}} - Xcode ${{matrix.config.xcode}} - ${{matrix.build_type}} 31 | runs-on: ${{matrix.config.os}} 32 | env: 33 | CMAKE_GENERATOR: "Xcode" 34 | DEVELOPER_DIR: "/Applications/Xcode_${{matrix.config.xcode}}.app/Contents/Developer" 35 | 36 | steps: 37 | - name: Checkout dynamic_bitset 38 | uses: actions/checkout@v4 39 | with: 40 | submodules: recursive 41 | path: dynamic_bitset 42 | 43 | - name: Setup CMake 44 | id: cmake 45 | uses: ./dynamic_bitset/.github/actions/setup_cmake 46 | with: 47 | cmake_version: ${{env.CMAKE_VERSION}} 48 | used_env: ${{matrix.config.os}} 49 | 50 | - name: CMake version 51 | run: ${{steps.cmake.outputs.cmake_binary}} --version 52 | 53 | - name: CTest version 54 | run: ${{steps.cmake.outputs.ctest_binary}} --version 55 | 56 | - name: Configure 57 | run: >- 58 | ${{steps.cmake.outputs.cmake_binary}} 59 | -S "${{github.workspace}}/dynamic_bitset" 60 | -B "${{github.workspace}}/dynamic_bitset/build" 61 | -D CMAKE_CONFIGURATION_TYPES=${{matrix.build_type}} 62 | -D CMAKE_BUILD_TYPE=${{matrix.build_type}} 63 | 64 | - name: Build 65 | run: >- 66 | ${{steps.cmake.outputs.cmake_binary}} 67 | --build "${{github.workspace}}/dynamic_bitset/build" 68 | --config ${{matrix.build_type}} 69 | --parallel $(nproc) 70 | 71 | - name: Run tests 72 | run: >- 73 | ${{steps.cmake.outputs.ctest_binary}} 74 | --test-dir "${{github.workspace}}/dynamic_bitset/build" 75 | --output-on-failure 76 | --parallel $(nproc) 77 | -------------------------------------------------------------------------------- /.github/workflows/windows-msvc.yml: -------------------------------------------------------------------------------- 1 | name: Windows Visual Studio 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | env: 8 | CMAKE_VERSION: 3.30.3 9 | 10 | jobs: 11 | build: 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | config: [ 16 | {os: windows-2019, generator: "Visual Studio 16 2019", generator_short: VS2019, toolset: v142}, 17 | {os: windows-2019, generator: "Visual Studio 16 2019", generator_short: VS2019, toolset: ClangCL}, 18 | {os: windows-2022, generator: "Visual Studio 17 2022", generator_short: VS2022, toolset: v143}, 19 | {os: windows-2022, generator: "Visual Studio 17 2022", generator_short: VS2022, toolset: ClangCL} 20 | ] 21 | architecture: [Win32, x64] 22 | build_type: [Debug, Release] 23 | name: ${{matrix.config.os}} - ${{matrix.config.generator_short}} - ${{matrix.config.toolset}} - ${{matrix.architecture}} - ${{matrix.build_type}} 24 | runs-on: ${{matrix.config.os}} 25 | env: 26 | CMAKE_GENERATOR: ${{matrix.config.generator}} 27 | CMAKE_GENERATOR_TOOLSET: ${{matrix.config.toolset}} 28 | CMAKE_GENERATOR_PLATFORM: ${{matrix.architecture}} 29 | 30 | steps: 31 | - name: Checkout dynamic_bitset 32 | uses: actions/checkout@v4 33 | with: 34 | submodules: recursive 35 | path: dynamic_bitset 36 | 37 | - name: Setup CMake 38 | id: cmake 39 | uses: ./dynamic_bitset/.github/actions/setup_cmake 40 | with: 41 | cmake_version: ${{env.CMAKE_VERSION}} 42 | used_env: ${{matrix.config.os}} 43 | 44 | - name: CMake version 45 | run: ${{steps.cmake.outputs.cmake_binary}} --version 46 | 47 | - name: CTest version 48 | run: ${{steps.cmake.outputs.ctest_binary}} --version 49 | 50 | - name: Configure 51 | run: >- 52 | ${{steps.cmake.outputs.cmake_binary}} 53 | -S "${{github.workspace}}/dynamic_bitset" 54 | -B "${{github.workspace}}/dynamic_bitset/build" 55 | -D CMAKE_CONFIGURATION_TYPES=${{matrix.build_type}} 56 | -D CMAKE_BUILD_TYPE=${{matrix.build_type}} 57 | 58 | - name: Build 59 | run: >- 60 | ${{steps.cmake.outputs.cmake_binary}} 61 | --build "${{github.workspace}}/dynamic_bitset/build" 62 | --config ${{matrix.build_type}} 63 | --parallel ${env:NUMBER_OF_PROCESSORS} 64 | 65 | - name: Run tests 66 | run: >- 67 | ${{steps.cmake.outputs.ctest_binary}} 68 | --test-dir "${{github.workspace}}/dynamic_bitset/build" 69 | --output-on-failure 70 | --parallel ${env:NUMBER_OF_PROCESSORS} 71 | -------------------------------------------------------------------------------- /.github/actions/setup_doxygen/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup Doxygen" 2 | description: "Setup Doxygen" 3 | inputs: 4 | doxygen_version: 5 | description: "Doxygen version" 6 | required: true 7 | doxygen_libclang_version: 8 | description: "libclang version used by Doxygen" 9 | required: true 10 | used_env: 11 | description: "Environment used with runs-on" 12 | required: true 13 | outputs: 14 | doxygen_install: 15 | description: "Doxygen installation path" 16 | value: ${{steps.configure.outputs.doxygen_install}} 17 | runs: 18 | using: "composite" 19 | steps: 20 | - name: Cache Doxygen 21 | id: cache 22 | uses: actions/cache@v4 23 | with: 24 | path: ${{github.workspace}}/doxygen 25 | key: doxygen-${{inputs.doxygen_version}}-${{inputs.used_env}} 26 | 27 | - name: Install dependencies 28 | shell: bash 29 | run: sudo apt install -y libclang1-${{inputs.doxygen_libclang_version}} libclang-cpp${{inputs.doxygen_libclang_version}} 30 | 31 | - name: Download Doxygen 32 | id: download 33 | if: ${{steps.cache.outputs.cache-hit != 'true'}} 34 | shell: cmake -P {0} 35 | run: | 36 | file(TO_CMAKE_PATH [=[${{github.workspace}}]=] workspace) 37 | if(NOT "${{runner.os}}" STREQUAL "Linux") 38 | message(FATAL_ERROR "Unsupported") 39 | endif() 40 | set(doxygen_dir "doxygen-${{inputs.doxygen_version}}") 41 | set(doxygen_url "https://sourceforge.net/projects/doxygen/files/rel-${{inputs.doxygen_version}}/doxygen-${{inputs.doxygen_version}}.linux.bin.tar.gz/download") 42 | message(STATUS "Download from: ${doxygen_url}") 43 | file(DOWNLOAD "${doxygen_url}" "${workspace}/doxygen.tar.gz" SHOW_PROGRESS) 44 | message(STATUS "Extract") 45 | execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf "${workspace}/doxygen.tar.gz") 46 | file(COPY "${workspace}/${doxygen_dir}" DESTINATION "${workspace}/doxygen") 47 | 48 | - name: Configure Doxygen 49 | id: configure 50 | shell: cmake -P {0} 51 | run: | 52 | file(TO_CMAKE_PATH [=[${{github.workspace}}]=] workspace) 53 | if(NOT "${{runner.os}}" STREQUAL "Linux") 54 | message(FATAL_ERROR "Unsupported") 55 | endif() 56 | set(doxygen_dir "doxygen-${{inputs.doxygen_version}}") 57 | file(APPEND "$ENV{GITHUB_OUTPUT}" "doxygen_install=${workspace}/doxygen/${doxygen_dir}\n") 58 | 59 | - name: Print version 60 | id: print 61 | shell: cmake -P {0} 62 | run: | 63 | execute_process(COMMAND ${{steps.configure.outputs.doxygen_install}}/bin/doxygen --version RESULT_VARIABLE result) 64 | if(NOT result EQUAL 0) 65 | message(FATAL_ERROR "Bad exit status") 66 | endif() 67 | -------------------------------------------------------------------------------- /tests/src/find_first_find_next.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #include "MultiTakeGenerator.hpp" 9 | #include "config.hpp" 10 | #include "utils.hpp" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #if DYNAMIC_BITSET_CAN_USE_STD_BITOPS 23 | # define FIND_FIRST_FIND_NEXT_TESTED_IMPL "C++20 binary operations" 24 | #elif DYNAMIC_BITSET_CAN_USE_GCC_BUILTIN 25 | # define FIND_FIRST_FIND_NEXT_TESTED_IMPL "gcc builtins" 26 | #elif DYNAMIC_BITSET_CAN_USE_CLANG_BUILTIN_CTZ 27 | # define FIND_FIRST_FIND_NEXT_TESTED_IMPL "clang builtins" 28 | #elif DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD 29 | # if DYNAMIC_BITSET_CAN_USE_MSVC_BUILTIN_BITSCANFORWARD64 30 | # define FIND_FIRST_FIND_NEXT_TESTED_IMPL "msvc builtins 32/64" 31 | # else 32 | # define FIND_FIRST_FIND_NEXT_TESTED_IMPL "msvc builtins 32" 33 | # endif 34 | #else 35 | # define FIND_FIRST_FIND_NEXT_TESTED_IMPL "base" 36 | #endif 37 | 38 | TEMPLATE_TEST_CASE("find_first find_next (" FIND_FIRST_FIND_NEXT_TESTED_IMPL ")", 39 | "[dynamic_bitset][builtin][c++20]", 40 | uint16_t, 41 | uint32_t, 42 | uint64_t) 43 | { 44 | SECTION("empty-bitset") 45 | { 46 | sul::dynamic_bitset bitset; 47 | 48 | REQUIRE(bitset.find_first() == bitset.npos); 49 | REQUIRE(bitset.find_next(0) == bitset.npos); 50 | } 51 | 52 | SECTION("non-empty bitset") 53 | { 54 | const std::tuple values = GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 55 | random(0, 5 * bits_number), 56 | random(0, 5 * bits_number))); 57 | const size_t first_bit_pos = std::get<0>(values); 58 | const size_t second_bit_pos = first_bit_pos + 1 + std::get<1>(values); 59 | CAPTURE(first_bit_pos, second_bit_pos); 60 | 61 | sul::dynamic_bitset bitset(second_bit_pos + 12); 62 | REQUIRE(bitset.find_first() == bitset.npos); 63 | bitset.set(first_bit_pos); 64 | bitset.set(second_bit_pos); 65 | REQUIRE(bitset.find_first() == first_bit_pos); 66 | REQUIRE(bitset.find_next(first_bit_pos) == second_bit_pos); 67 | REQUIRE(bitset.find_next(second_bit_pos) == bitset.npos); 68 | REQUIRE(bitset.find_next(bitset.size()) == bitset.npos); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Coverage 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | env: 8 | CMAKE_VERSION: 3.30.3 9 | 10 | jobs: 11 | build: 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | config: [ 16 | {os: ubuntu-24.04, compiler_name: gcc, c_compiler: gcc-13, cxx_compiler: g++-13} 17 | ] 18 | name: ${{matrix.config.os}} - ${{matrix.config.compiler_name}} - coverage 19 | runs-on: ${{matrix.config.os}} 20 | env: 21 | CMAKE_GENERATOR: "Unix Makefiles" 22 | CC: ${{matrix.config.c_compiler}} 23 | CXX: ${{matrix.config.cxx_compiler}} 24 | 25 | steps: 26 | - name: Checkout dynamic_bitset 27 | uses: actions/checkout@v4 28 | with: 29 | submodules: recursive 30 | path: dynamic_bitset 31 | 32 | - name: Setup CMake 33 | id: cmake 34 | uses: ./dynamic_bitset/.github/actions/setup_cmake 35 | with: 36 | cmake_version: ${{env.CMAKE_VERSION}} 37 | used_env: ${{matrix.config.os}} 38 | 39 | - name: CMake version 40 | run: ${{steps.cmake.outputs.cmake_binary}} --version 41 | 42 | - name: CTest version 43 | run: ${{steps.cmake.outputs.ctest_binary}} --version 44 | 45 | - name: Make version 46 | run: make --version 47 | 48 | - name: C compiler version 49 | run: ${CC} --version 50 | 51 | - name: C++ compiler version 52 | run: ${CXX} --version 53 | 54 | - name: Configure 55 | run: >- 56 | ${{steps.cmake.outputs.cmake_binary}} 57 | -S "${{github.workspace}}/dynamic_bitset" 58 | -B "${{github.workspace}}/dynamic_bitset/build" 59 | -D CMAKE_CONFIGURATION_TYPES=Release 60 | -D CMAKE_BUILD_TYPE=Release 61 | -D DYNAMICBITSET_ENABLE_COVERAGE=ON 62 | 63 | - name: Build 64 | run: >- 65 | ${{steps.cmake.outputs.cmake_binary}} 66 | --build "${{github.workspace}}/dynamic_bitset/build" 67 | --config Release 68 | --parallel $(nproc) 69 | 70 | - name: Run tests 71 | run: >- 72 | ${{steps.cmake.outputs.ctest_binary}} 73 | --test-dir "${{github.workspace}}/dynamic_bitset/build" 74 | --output-on-failure 75 | --parallel $(nproc) 76 | 77 | - name: Generate coverage report 78 | run: | 79 | sudo apt install lcov 80 | lcov --ignore-errors mismatch --directory "${{github.workspace}}/dynamic_bitset/build" --capture --output-file "${{github.workspace}}/coverage.info" 81 | lcov --extract "${{github.workspace}}/coverage.info" "*/dynamic_bitset.hpp" --output-file "${{github.workspace}}/coverage.info" 82 | 83 | - name: Upload coverage to Codecov 84 | uses: codecov/codecov-action@v4 85 | with: 86 | fail_ci_if_error: true 87 | file: ${{github.workspace}}/coverage.info 88 | root_dir: ${{github.workspace}}/dynamic_bitset 89 | token: ${{ secrets.CODECOV_TOKEN }} 90 | plugin: noop 91 | plugins: noop 92 | verbose: true 93 | -------------------------------------------------------------------------------- /.github/workflows/windows-msys2.yml: -------------------------------------------------------------------------------- 1 | name: Windows MSYS2 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | env: 8 | CMAKE_VERSION: 3.30.3 9 | CCACHE_VERSION: 4.10.2 10 | 11 | jobs: 12 | build: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: [windows-2019, windows-2022] 17 | sys: [mingw64, mingw32, clang64, clang32, ucrt64] 18 | build_type: [Debug, Release] 19 | name: ${{matrix.os}} - ${{matrix.sys}} - ${{matrix.build_type}} 20 | runs-on: ${{matrix.os}} 21 | defaults: 22 | run: 23 | shell: msys2 {0} 24 | 25 | steps: 26 | - name: Checkout dynamic_bitset 27 | uses: actions/checkout@v4 28 | with: 29 | submodules: recursive 30 | path: dynamic_bitset 31 | 32 | - name: Setup build environment 33 | uses: msys2/setup-msys2@v2 34 | with: 35 | msystem: ${{matrix.sys}} 36 | update: true 37 | pacboy: >- 38 | toolchain:p 39 | ninja:p 40 | 41 | - name: Setup CMake 42 | id: cmake 43 | uses: ./dynamic_bitset/.github/actions/setup_cmake 44 | with: 45 | cmake_version: ${{env.CMAKE_VERSION}} 46 | used_env: ${{matrix.os}} 47 | 48 | - name: Setup ccache 49 | id: ccache 50 | uses: ./dynamic_bitset/.github/actions/setup_ccache 51 | with: 52 | ccache_version: ${{env.CCACHE_VERSION}} 53 | used_env: ${{matrix.os}} 54 | cache_id: ${{matrix.os}}-${{matrix.sys}}-${{matrix.build_type}} 55 | 56 | - name: CMake version 57 | run: ${{steps.cmake.outputs.cmake_binary}} --version 58 | 59 | - name: CTest version 60 | run: ${{steps.cmake.outputs.ctest_binary}} --version 61 | 62 | - name: Ccache version 63 | run: ${{steps.ccache.outputs.ccache_binary}} --version 64 | 65 | - name: Ninja version 66 | run: ninja --version 67 | 68 | - name: C compiler version 69 | run: cc --version 70 | 71 | - name: C++ compiler version 72 | run: c++ --version 73 | 74 | - name: Configure 75 | run: >- 76 | ${{steps.cmake.outputs.cmake_binary}} 77 | -S "${{github.workspace}}/dynamic_bitset" 78 | -B "${{github.workspace}}/dynamic_bitset/build" 79 | -G Ninja 80 | -D CMAKE_CONFIGURATION_TYPES=${{matrix.build_type}} 81 | -D CMAKE_BUILD_TYPE=${{matrix.build_type}} 82 | -D CMAKE_C_COMPILER_LAUNCHER=${{steps.ccache.outputs.ccache_binary}} 83 | -D CMAKE_CXX_COMPILER_LAUNCHER=${{steps.ccache.outputs.ccache_binary}} 84 | 85 | - name: Build 86 | run: >- 87 | ${{steps.cmake.outputs.cmake_binary}} 88 | --build "${{github.workspace}}/dynamic_bitset/build" 89 | --config ${{matrix.build_type}} 90 | --parallel $(nproc) 91 | 92 | - name: Ccache stats 93 | run: >- 94 | ${{steps.ccache.outputs.ccache_binary}} --show-stats 95 | 96 | - name: Run tests 97 | run: >- 98 | ${{steps.cmake.outputs.ctest_binary}} 99 | --test-dir "${{github.workspace}}/dynamic_bitset/build" 100 | --output-on-failure 101 | --parallel $(nproc) 102 | -------------------------------------------------------------------------------- /tests/include/RandomBitsetStringGenerator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #ifndef DYNAMIC_BITSET_RANDOMBITSETSTRINGGENERATOR_HPP 9 | #define DYNAMIC_BITSET_RANDOMBITSETSTRINGGENERATOR_HPP 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | Catch::Generators::GeneratorWrapper 18 | randomBitsetString(uint32_t seed = Catch::Generators::Detail::getSeed()); 19 | 20 | Catch::Generators::GeneratorWrapper 21 | randomBitsetString(std::string::size_type min_size, 22 | std::string::size_type max_size, 23 | uint32_t seed = Catch::Generators::Detail::getSeed()); 24 | 25 | class RandomBitsetStringGenerator : public Catch::Generators::IGenerator 26 | { 27 | public: 28 | typedef std::string::size_type size_type; 29 | static constexpr size_type default_min_size = 1; 30 | static constexpr size_type default_max_size = 256; 31 | 32 | explicit RandomBitsetStringGenerator(uint32_t seed = Catch::Generators::Detail::getSeed()); 33 | RandomBitsetStringGenerator(size_type min_size, 34 | size_type max_size, 35 | uint32_t seed = Catch::Generators::Detail::getSeed()); 36 | 37 | const std::string& get() const override; 38 | bool next() override; 39 | 40 | private: 41 | Catch::SimplePcg32 m_rand; 42 | Catch::uniform_integer_distribution m_size_dist; 43 | Catch::uniform_integer_distribution m_bit_dist; 44 | std::string m_current_bitset; 45 | }; 46 | 47 | inline RandomBitsetStringGenerator::RandomBitsetStringGenerator(uint32_t seed) 48 | : m_rand(seed) 49 | , m_size_dist(default_min_size, default_max_size) 50 | , m_bit_dist('0', '1') 51 | , m_current_bitset() 52 | { 53 | next(); 54 | } 55 | 56 | inline RandomBitsetStringGenerator::RandomBitsetStringGenerator(size_type min_size, size_type max_size, uint32_t seed) 57 | : m_rand(seed) 58 | , m_size_dist(min_size, max_size) 59 | , m_bit_dist('0', '1') 60 | , m_current_bitset() 61 | { 62 | next(); 63 | } 64 | 65 | inline const std::string& RandomBitsetStringGenerator::get() const 66 | { 67 | return m_current_bitset; 68 | } 69 | 70 | inline bool RandomBitsetStringGenerator::next() 71 | { 72 | const size_type bitset_size = m_size_dist(m_rand); 73 | m_current_bitset.clear(); 74 | m_current_bitset.reserve(bitset_size); 75 | for(size_t i = 0; i < bitset_size; ++i) 76 | { 77 | m_current_bitset.push_back(m_bit_dist(m_rand)); 78 | } 79 | return true; 80 | } 81 | 82 | inline Catch::Generators::GeneratorWrapper randomBitsetString(uint32_t seed) 83 | { 84 | return Catch::Generators::GeneratorWrapper( 85 | Catch::Detail::make_unique(seed)); 86 | } 87 | 88 | inline Catch::Generators::GeneratorWrapper 89 | randomBitsetString(std::string::size_type min_size, std::string::size_type max_size, uint32_t seed) 90 | { 91 | return Catch::Generators::GeneratorWrapper( 92 | Catch::Detail::make_unique(min_size, max_size, seed)); 93 | } 94 | 95 | #endif // DYNAMIC_BITSET_RANDOMBITSETSTRINGGENERATOR_HPP 96 | -------------------------------------------------------------------------------- /tests/include/MultiTakeGenerator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #ifndef DYNAMIC_BITSET_MULTITAKEGENERATOR_HPP 9 | #define DYNAMIC_BITSET_MULTITAKEGENERATOR_HPP 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | template 18 | constexpr Catch::Generators::GeneratorWrapper> 19 | multitake(size_t target, Catch::Generators::GeneratorWrapper&&... generators); 20 | 21 | template 22 | class MultiTakeGenerator : public Catch::Generators::IGenerator> 23 | { 24 | 25 | public: 26 | explicit constexpr MultiTakeGenerator(size_t target, Catch::Generators::GeneratorWrapper&&... generators); 27 | 28 | constexpr std::tuple const& get() const override; 29 | 30 | constexpr bool next() override; 31 | 32 | private: 33 | std::tuple...> m_generators; 34 | std::tuple m_current; 35 | size_t m_returned; 36 | size_t m_target; 37 | 38 | constexpr bool generators_next(); 39 | 40 | template 41 | constexpr bool generators_next_impl(std::index_sequence); 42 | 43 | constexpr std::tuple generators_get(); 44 | 45 | template 46 | constexpr std::tuple generators_get_impl(std::index_sequence); 47 | }; 48 | 49 | template 50 | constexpr MultiTakeGenerator::MultiTakeGenerator(size_t target, 51 | Catch::Generators::GeneratorWrapper&&... generators) 52 | : m_generators(std::move(generators)...) 53 | , m_current() 54 | , m_returned(0) 55 | , m_target(target) 56 | { 57 | assert(target != 0 && "Empty generators are not allowed"); 58 | next(); 59 | } 60 | 61 | template 62 | constexpr std::tuple const& MultiTakeGenerator::get() const 63 | { 64 | return m_current; 65 | } 66 | 67 | template 68 | constexpr bool MultiTakeGenerator::next() 69 | { 70 | ++m_returned; 71 | if(m_returned >= m_target) 72 | { 73 | return false; 74 | } 75 | 76 | const bool success = generators_next(); 77 | // If one of the underlying generators does not contain enough values 78 | // then we cut short as well 79 | if(!success) 80 | { 81 | m_returned = m_target; 82 | } 83 | else 84 | { 85 | // update current 86 | m_current = generators_get(); 87 | } 88 | return success; 89 | } 90 | 91 | template 92 | constexpr bool MultiTakeGenerator::generators_next() 93 | { 94 | return generators_next_impl(std::make_index_sequence()); 95 | } 96 | 97 | template 98 | template 99 | constexpr bool MultiTakeGenerator::generators_next_impl(std::index_sequence) 100 | { 101 | return (std::get(m_generators).next() && ...); 102 | } 103 | 104 | template 105 | constexpr std::tuple MultiTakeGenerator::generators_get() 106 | { 107 | return generators_get_impl(std::make_index_sequence()); 108 | } 109 | 110 | template 111 | template 112 | constexpr std::tuple MultiTakeGenerator::generators_get_impl(std::index_sequence) 113 | { 114 | return std::make_tuple(std::get(m_generators).get()...); 115 | } 116 | 117 | template 118 | constexpr Catch::Generators::GeneratorWrapper> 119 | multitake(size_t target, Catch::Generators::GeneratorWrapper&&... generators) 120 | { 121 | return Catch::Generators::GeneratorWrapper>( 122 | Catch::Detail::make_unique>(target, std::move(generators)...)); 123 | } 124 | 125 | #endif // DYNAMIC_BITSET_MULTITAKEGENERATOR_HPP 126 | -------------------------------------------------------------------------------- /tests/include/RandomChunkGenerator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #ifndef DYNAMIC_BITSET_RANDOMCHUNKGENERATOR_HPP 9 | #define DYNAMIC_BITSET_RANDOMCHUNKGENERATOR_HPP 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | template 18 | constexpr Catch::Generators::GeneratorWrapper> 19 | randomChunk(typename std::vector::size_type min_chunk_size, 20 | typename std::vector::size_type max_chunk_size, 21 | Catch::Generators::GeneratorWrapper&& generator, 22 | uint32_t seed = Catch::Generators::Detail::getSeed()); 23 | 24 | template 25 | class RandomChunkGenerator final : public Catch::Generators::IGenerator> 26 | { 27 | public: 28 | using size_type = typename std::vector::size_type; 29 | 30 | constexpr RandomChunkGenerator(size_type min_chunk_size, 31 | size_type max_chunk_size, 32 | Catch::Generators::GeneratorWrapper&& generator, 33 | uint32_t seed = Catch::Generators::Detail::getSeed()); 34 | 35 | constexpr std::vector const& get() const override; 36 | 37 | constexpr bool next() override; 38 | 39 | private: 40 | Catch::SimplePcg32 m_rand; 41 | Catch::uniform_integer_distribution m_size_dist; 42 | std::vector m_chunk; 43 | Catch::Generators::GeneratorWrapper m_generator; 44 | }; 45 | 46 | template 47 | constexpr RandomChunkGenerator::RandomChunkGenerator(size_type min_chunk_size, 48 | size_type max_chunk_size, 49 | Catch::Generators::GeneratorWrapper&& generator, 50 | uint32_t seed) 51 | : m_rand(seed) 52 | , m_size_dist(min_chunk_size, max_chunk_size) 53 | , m_chunk() 54 | , m_generator(std::move(generator)) 55 | { 56 | const size_type size = m_size_dist(m_rand); 57 | m_chunk.reserve(size); 58 | if(size == 0) 59 | { 60 | return; 61 | } 62 | 63 | m_chunk.push_back(m_generator.get()); 64 | for(size_type i = 1; i < min_chunk_size; ++i) 65 | { 66 | assert(m_generator.next() && "Not enough values to initialize the first chunk"); 67 | m_chunk.push_back(m_generator.get()); 68 | } 69 | for(size_type i = min_chunk_size; i < size; ++i) 70 | { 71 | if(m_generator.next()) 72 | { 73 | m_chunk.push_back(m_generator.get()); 74 | } 75 | } 76 | } 77 | 78 | template 79 | constexpr const std::vector& RandomChunkGenerator::get() const 80 | { 81 | return m_chunk; 82 | } 83 | 84 | template 85 | constexpr bool RandomChunkGenerator::next() 86 | { 87 | const size_type size = m_size_dist(m_rand); 88 | m_chunk.clear(); 89 | m_chunk.reserve(size); 90 | for(size_type i = 0; i < size; ++i) 91 | { 92 | if(!m_generator.next()) 93 | { 94 | return false; 95 | } 96 | m_chunk.push_back(m_generator.get()); 97 | } 98 | return true; 99 | } 100 | 101 | template 102 | constexpr Catch::Generators::GeneratorWrapper> 103 | randomChunk(typename std::vector::size_type min_chunk_size, 104 | typename std::vector::size_type max_chunk_size, 105 | Catch::Generators::GeneratorWrapper&& generator, 106 | uint32_t seed) 107 | { 108 | return Catch::Generators::GeneratorWrapper>( 109 | Catch::Detail::make_unique>(min_chunk_size, max_chunk_size, std::move(generator), seed)); 110 | } 111 | 112 | #endif // DYNAMIC_BITSET_RANDOMCHUNKGENERATOR_HPP 113 | -------------------------------------------------------------------------------- /.github/actions/setup_cmake/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup CMake" 2 | description: "Setup CMake" 3 | inputs: 4 | cmake_version: 5 | description: "CMake version" 6 | required: true 7 | used_env: 8 | description: "Environment used with runs-on" 9 | required: true 10 | outputs: 11 | cmake_binary: 12 | description: "CMake binary path" 13 | value: ${{steps.configure.outputs.cmake_binary}} 14 | ctest_binary: 15 | description: "CTest binary path" 16 | value: ${{steps.configure.outputs.ctest_binary}} 17 | runs: 18 | using: "composite" 19 | steps: 20 | - name: Cache CMake 21 | id: cache 22 | uses: actions/cache@v4 23 | with: 24 | path: ${{github.workspace}}/cmake 25 | key: cmake-${{inputs.cmake_version}}-${{inputs.used_env}} 26 | 27 | - name: Download CMake 28 | id: download 29 | if: ${{steps.cache.outputs.cache-hit != 'true'}} 30 | shell: cmake -P {0} 31 | run: | 32 | file(TO_CMAKE_PATH [=[${{github.workspace}}]=] workspace) 33 | message(STATUS "Using host CMake version: ${CMAKE_VERSION}") 34 | if("${{runner.os}}" STREQUAL "Windows") 35 | set(cmake_suffix "windows-x86_64.zip") 36 | set(cmake_dir "cmake-${{inputs.cmake_version}}-windows-x86_64") 37 | set(cmake_bin_dir "cmake-${{inputs.cmake_version}}-windows-x86_64/bin") 38 | elseif("${{runner.os}}" STREQUAL "Linux") 39 | set(cmake_suffix "linux-x86_64.tar.gz") 40 | set(cmake_dir "cmake-${{inputs.cmake_version}}-linux-x86_64") 41 | set(cmake_bin_dir "cmake-${{inputs.cmake_version}}-linux-x86_64/bin") 42 | elseif("${{runner.os}}" STREQUAL "macOS") 43 | set(cmake_suffix "macos-universal.tar.gz") 44 | set(cmake_dir "cmake-${{inputs.cmake_version}}-macos-universal") 45 | set(cmake_bin_dir "cmake-${{inputs.cmake_version}}-macos-universal/CMake.app/Contents/bin") 46 | endif() 47 | set(cmake_url "https://github.com/Kitware/CMake/releases/download/v${{inputs.cmake_version}}/cmake-${{inputs.cmake_version}}-${cmake_suffix}") 48 | message(STATUS "Download from: ${cmake_url}") 49 | file(DOWNLOAD "${cmake_url}" "${workspace}/cmake.zip" SHOW_PROGRESS) 50 | message(STATUS "Extract") 51 | execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf "${workspace}/cmake.zip") 52 | file(COPY "${workspace}/${cmake_dir}" DESTINATION "${workspace}/cmake") 53 | if(NOT "${{runner.os}}" STREQUAL "Windows") 54 | execute_process(COMMAND chmod +x "${workspace}/cmake/${cmake_bin_dir}/cmake") 55 | execute_process(COMMAND chmod +x "${workspace}/cmake/${cmake_bin_dir}/ctest") 56 | endif() 57 | 58 | - name: Configure CMake 59 | id: configure 60 | shell: cmake -P {0} 61 | run: | 62 | file(TO_CMAKE_PATH [=[${{github.workspace}}]=] workspace) 63 | if("${{runner.os}}" STREQUAL "Windows") 64 | set(cmake_bin_dir "cmake-${{inputs.cmake_version}}-windows-x86_64/bin") 65 | elseif("${{runner.os}}" STREQUAL "Linux") 66 | set(cmake_bin_dir "cmake-${{inputs.cmake_version}}-linux-x86_64/bin") 67 | elseif("${{runner.os}}" STREQUAL "macOS") 68 | set(cmake_bin_dir "cmake-${{inputs.cmake_version}}-macos-universal/CMake.app/Contents/bin") 69 | endif() 70 | set(cmake_binary "${workspace}/cmake/${cmake_bin_dir}/cmake") 71 | set(ctest_binary "${workspace}/cmake/${cmake_bin_dir}/ctest") 72 | message(STATUS "CMake binary: ${cmake_binary}") 73 | file(APPEND "$ENV{GITHUB_OUTPUT}" "cmake_binary=${cmake_binary}\n") 74 | message(STATUS "CTest binary: ${ctest_binary}") 75 | file(APPEND "$ENV{GITHUB_OUTPUT}" "ctest_binary=${ctest_binary}\n") 76 | 77 | - name: Print version 78 | id: print 79 | shell: cmake -P {0} 80 | run: | 81 | execute_process(COMMAND ${{steps.configure.outputs.cmake_binary}} --version RESULT_VARIABLE result) 82 | if(NOT result EQUAL 0) 83 | message(FATAL_ERROR "Bad exit status") 84 | endif() 85 | execute_process(COMMAND ${{steps.configure.outputs.ctest_binary}} --version RESULT_VARIABLE result) 86 | if(NOT result EQUAL 0) 87 | message(FATAL_ERROR "Bad exit status") 88 | endif() 89 | -------------------------------------------------------------------------------- /tests/include/RandomDynamicBitsetGenerator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #ifndef DYNAMIC_BITSET_RANDOMDYNAMICBITSETGENERATOR_HPP 9 | #define DYNAMIC_BITSET_RANDOMDYNAMICBITSETGENERATOR_HPP 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | template 19 | constexpr Catch::Generators::GeneratorWrapper> 20 | randomDynamicBitset(uint32_t seed = Catch::Generators::Detail::getSeed()); 21 | 22 | template 23 | constexpr Catch::Generators::GeneratorWrapper> 24 | randomDynamicBitset(typename sul::dynamic_bitset::size_type min_size, 25 | typename sul::dynamic_bitset::size_type max_size, 26 | uint32_t seed = Catch::Generators::Detail::getSeed()); 27 | 28 | template 29 | class RandomDynamicBitsetGenerator : public Catch::Generators::IGenerator> 30 | { 31 | public: 32 | typedef typename sul::dynamic_bitset::size_type size_type; 33 | static constexpr size_type default_min_size = 1; 34 | static constexpr size_type default_max_size = 8 * std::numeric_limits::digits; 35 | 36 | constexpr explicit RandomDynamicBitsetGenerator(uint32_t seed = Catch::Generators::Detail::getSeed()); 37 | constexpr RandomDynamicBitsetGenerator(size_type min_size, 38 | size_type max_size, 39 | uint32_t seed = Catch::Generators::Detail::getSeed()); 40 | 41 | constexpr const sul::dynamic_bitset& get() const override; 42 | constexpr bool next() override; 43 | 44 | private: 45 | std::minstd_rand m_rand; 46 | std::uniform_int_distribution m_size_dist; 47 | std::uniform_int_distribution m_block_dist; 48 | sul::dynamic_bitset m_current_bitset; 49 | }; 50 | 51 | template 52 | constexpr RandomDynamicBitsetGenerator::RandomDynamicBitsetGenerator(uint32_t seed) 53 | : m_rand(seed) 54 | , m_size_dist(default_min_size, default_max_size) 55 | , m_block_dist() 56 | , m_current_bitset() 57 | { 58 | next(); 59 | } 60 | 61 | template 62 | constexpr RandomDynamicBitsetGenerator::RandomDynamicBitsetGenerator(size_type min_size, 63 | size_type max_size, 64 | uint32_t seed) 65 | : m_rand(seed) 66 | , m_size_dist(min_size, max_size) 67 | , m_block_dist() 68 | , m_current_bitset() 69 | { 70 | next(); 71 | } 72 | 73 | template 74 | constexpr const sul::dynamic_bitset& RandomDynamicBitsetGenerator::get() const 75 | { 76 | return m_current_bitset; 77 | } 78 | 79 | template 80 | constexpr bool RandomDynamicBitsetGenerator::next() 81 | { 82 | const size_type bitset_size = m_size_dist(m_rand); 83 | m_current_bitset.clear(); 84 | for(size_t i = 0; i < (bitset_size / m_current_bitset.bits_per_block) + 1; ++i) 85 | { 86 | m_current_bitset.append(m_block_dist(m_rand)); 87 | } 88 | m_current_bitset.resize(bitset_size); 89 | return true; 90 | } 91 | 92 | template 93 | constexpr Catch::Generators::GeneratorWrapper> randomDynamicBitset(uint32_t seed) 94 | { 95 | return Catch::Generators::GeneratorWrapper>( 96 | Catch::Detail::make_unique>(seed)); 97 | } 98 | 99 | template 100 | constexpr Catch::Generators::GeneratorWrapper> 101 | randomDynamicBitset(typename sul::dynamic_bitset::size_type min_size, 102 | typename sul::dynamic_bitset::size_type max_size, 103 | uint32_t seed) 104 | { 105 | return Catch::Generators::GeneratorWrapper>( 106 | Catch::Detail::make_unique>(min_size, max_size, seed)); 107 | } 108 | 109 | #endif // DYNAMIC_BITSET_RANDOMDYNAMICBITSETGENERATOR_HPP 110 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) # For target_link_options 2 | 3 | # Options 4 | option(DYNAMICBITSET_ENABLE_COVERAGE "Enable coverage information generation" OFF) 5 | 6 | # Check dynamic_bitset 7 | if(NOT TARGET dynamic_bitset) 8 | message(FATAL_ERROR "dynamic_bitset target required for the tests") 9 | endif() 10 | 11 | # Project declaration 12 | project( 13 | dynamic_bitset_tests 14 | DESCRIPTION "C++ dynamic bitset tests" 15 | LANGUAGES CXX 16 | ) 17 | 18 | # Declare tests targets 19 | add_executable(dynamic_bitset_tests_base) 20 | add_executable(dynamic_bitset_tests_libpopcnt) 21 | add_executable(dynamic_bitset_tests_std_bitops) 22 | add_executable(dynamic_bitset_tests_builtins) 23 | add_executable(dynamic_bitset_tests_builtins_msvc_32) 24 | 25 | # Add sources 26 | file(GLOB_RECURSE sources "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") 27 | file(GLOB_RECURSE includes "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp") 28 | target_sources( 29 | dynamic_bitset_tests_base PRIVATE 30 | ${includes} 31 | ${sources} 32 | ) 33 | target_sources( 34 | dynamic_bitset_tests_libpopcnt PRIVATE 35 | ${includes} 36 | "${CMAKE_CURRENT_SOURCE_DIR}/src/count.cpp" 37 | ) 38 | target_sources( 39 | dynamic_bitset_tests_std_bitops PRIVATE 40 | ${includes} 41 | "${CMAKE_CURRENT_SOURCE_DIR}/src/count.cpp" 42 | "${CMAKE_CURRENT_SOURCE_DIR}/src/find_first_find_next.cpp" 43 | ) 44 | target_sources( 45 | dynamic_bitset_tests_builtins PRIVATE 46 | ${includes} 47 | "${CMAKE_CURRENT_SOURCE_DIR}/src/count.cpp" 48 | "${CMAKE_CURRENT_SOURCE_DIR}/src/find_first_find_next.cpp" 49 | ) 50 | target_sources( 51 | dynamic_bitset_tests_builtins_msvc_32 PRIVATE 52 | ${includes} 53 | "${CMAKE_CURRENT_SOURCE_DIR}/src/find_first_find_next.cpp" 54 | ) 55 | source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${includes} ${sources}) 56 | 57 | foreach( 58 | target 59 | dynamic_bitset_tests_base 60 | dynamic_bitset_tests_libpopcnt 61 | dynamic_bitset_tests_std_bitops 62 | dynamic_bitset_tests_builtins 63 | dynamic_bitset_tests_builtins_msvc_32 64 | ) 65 | # Set target IDE folder 66 | set_target_properties(${target} PROPERTIES FOLDER "dynamic_bitset/tests") 67 | 68 | # Add includes 69 | target_include_directories( 70 | ${target} PRIVATE 71 | "${CMAKE_CURRENT_SOURCE_DIR}/include" 72 | ) 73 | 74 | # Link dynamic_bitset 75 | target_link_libraries(${target} PRIVATE dynamic_bitset) 76 | 77 | # Link Catch2 78 | target_link_libraries(${target} PRIVATE Catch2::Catch2WithMain) 79 | 80 | # Enable coverage information generation? 81 | if(DYNAMICBITSET_ENABLE_COVERAGE) 82 | target_compile_options(${target} PRIVATE "--coverage") 83 | target_link_options(${target} PRIVATE "--coverage") 84 | message(STATUS "${target}: enabled coverage") 85 | endif() 86 | 87 | # Require C++17/20 88 | if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES) 89 | target_compile_features(${target} PRIVATE cxx_std_20) 90 | else() 91 | target_compile_features(${target} PRIVATE cxx_std_17) 92 | endif() 93 | 94 | # Discover tests 95 | catch_discover_tests(${target}) 96 | endforeach() 97 | 98 | # Add compile definitions 99 | target_compile_definitions( 100 | dynamic_bitset_tests_base PRIVATE 101 | DYNAMIC_BITSET_NO_LIBPOPCNT 102 | DYNAMIC_BITSET_NO_STD_BITOPS 103 | DYNAMIC_BITSET_NO_COMPILER_BUILTIN 104 | ) 105 | target_compile_definitions( 106 | dynamic_bitset_tests_libpopcnt PRIVATE 107 | DYNAMIC_BITSET_NO_STD_BITOPS 108 | DYNAMIC_BITSET_NO_COMPILER_BUILTIN 109 | ) 110 | target_compile_definitions( 111 | dynamic_bitset_tests_std_bitops PRIVATE 112 | DYNAMIC_BITSET_NO_LIBPOPCNT 113 | DYNAMIC_BITSET_NO_COMPILER_BUILTIN 114 | ) 115 | target_compile_definitions( 116 | dynamic_bitset_tests_builtins PRIVATE 117 | DYNAMIC_BITSET_NO_LIBPOPCNT 118 | DYNAMIC_BITSET_NO_STD_BITOPS 119 | ) 120 | target_compile_definitions( 121 | dynamic_bitset_tests_builtins_msvc_32 PRIVATE 122 | DYNAMIC_BITSET_NO_LIBPOPCNT 123 | DYNAMIC_BITSET_NO_STD_BITOPS 124 | DYNAMIC_BITSET_NO_MSVC_BUILTIN_BITSCANFORWARD64 125 | ) 126 | 127 | # Generate format target? 128 | if(DYNAMICBITSET_FORMAT_TARGET) 129 | add_custom_target( 130 | format-dynamic_bitset_tests 131 | COMMAND "${CLANG_FORMAT}" -style=file -i ${includes} ${sources} 132 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 133 | VERBATIM 134 | ) 135 | set_target_properties(format-dynamic_bitset_tests PROPERTIES FOLDER "dynamic_bitset/format") 136 | endif() 137 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | env: 8 | CMAKE_VERSION: 3.30.3 9 | CCACHE_VERSION: 4.10.2 10 | 11 | jobs: 12 | build: 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | config: [ 17 | {os: ubuntu-20.04, compiler_name: gcc-10, c_compiler: gcc-10, cxx_compiler: g++-10}, 18 | {os: ubuntu-20.04, compiler_name: clang-10, c_compiler: clang-10, cxx_compiler: clang++-10}, 19 | {os: ubuntu-20.04, compiler_name: clang-11, c_compiler: clang-11, cxx_compiler: clang++-11}, 20 | {os: ubuntu-20.04, compiler_name: clang-12, c_compiler: clang-12, cxx_compiler: clang++-12}, 21 | {os: ubuntu-22.04, compiler_name: gcc-10, c_compiler: gcc-10, cxx_compiler: g++-10}, 22 | {os: ubuntu-22.04, compiler_name: gcc-11, c_compiler: gcc-11, cxx_compiler: g++-11}, 23 | {os: ubuntu-22.04, compiler_name: gcc-12, c_compiler: gcc-12, cxx_compiler: g++-12}, 24 | {os: ubuntu-22.04, compiler_name: clang-13, c_compiler: clang-13, cxx_compiler: clang++-13}, 25 | {os: ubuntu-22.04, compiler_name: clang-14, c_compiler: clang-14, cxx_compiler: clang++-14}, 26 | {os: ubuntu-22.04, compiler_name: clang-15, c_compiler: clang-15, cxx_compiler: clang++-15}, 27 | {os: ubuntu-24.04, compiler_name: gcc-12, c_compiler: gcc-12, cxx_compiler: g++-12}, 28 | {os: ubuntu-24.04, compiler_name: gcc-13, c_compiler: gcc-13, cxx_compiler: g++-13}, 29 | {os: ubuntu-24.04, compiler_name: gcc-14, c_compiler: gcc-14, cxx_compiler: g++-14}, 30 | {os: ubuntu-24.04, compiler_name: clang-16, c_compiler: clang-16, cxx_compiler: clang++-16}, 31 | {os: ubuntu-24.04, compiler_name: clang-17, c_compiler: clang-17, cxx_compiler: clang++-17}, 32 | {os: ubuntu-24.04, compiler_name: clang-18, c_compiler: clang-18, cxx_compiler: clang++-18}, 33 | ] 34 | build_type: [Debug, Release, Sanitize] 35 | name: ${{matrix.config.os}} - ${{matrix.config.compiler_name}} - ${{matrix.build_type}} 36 | runs-on: ${{matrix.config.os}} 37 | env: 38 | CMAKE_GENERATOR: "Unix Makefiles" 39 | CC: ${{matrix.config.c_compiler}} 40 | CXX: ${{matrix.config.cxx_compiler}} 41 | 42 | steps: 43 | - name: Checkout dynamic_bitset 44 | uses: actions/checkout@v4 45 | with: 46 | submodules: recursive 47 | path: dynamic_bitset 48 | 49 | - name: Setup CMake 50 | id: cmake 51 | uses: ./dynamic_bitset/.github/actions/setup_cmake 52 | with: 53 | cmake_version: ${{env.CMAKE_VERSION}} 54 | used_env: ${{matrix.config.os}} 55 | 56 | - name: Setup ccache 57 | id: ccache 58 | uses: ./dynamic_bitset/.github/actions/setup_ccache 59 | with: 60 | ccache_version: ${{env.CCACHE_VERSION}} 61 | used_env: ${{matrix.config.os}} 62 | cache_id: ${{matrix.config.os}}-${{matrix.config.compiler_name}}-${{matrix.build_type}} 63 | 64 | - name: CMake version 65 | run: ${{steps.cmake.outputs.cmake_binary}} --version 66 | 67 | - name: CTest version 68 | run: ${{steps.cmake.outputs.ctest_binary}} --version 69 | 70 | - name: Ccache version 71 | run: ${{steps.ccache.outputs.ccache_binary}} --version 72 | 73 | - name: Make version 74 | run: make --version 75 | 76 | - name: C compiler version 77 | run: ${CC} --version 78 | 79 | - name: C++ compiler version 80 | run: ${CXX} --version 81 | 82 | - name: Configure 83 | run: >- 84 | ${{steps.cmake.outputs.cmake_binary}} 85 | -S "${{github.workspace}}/dynamic_bitset" 86 | -B "${{github.workspace}}/dynamic_bitset/build" 87 | -D CMAKE_CONFIGURATION_TYPES=${{matrix.build_type}} 88 | -D CMAKE_BUILD_TYPE=${{matrix.build_type}} 89 | -D CMAKE_C_COMPILER_LAUNCHER=${{steps.ccache.outputs.ccache_binary}} 90 | -D CMAKE_CXX_COMPILER_LAUNCHER=${{steps.ccache.outputs.ccache_binary}} 91 | 92 | - name: Build 93 | run: >- 94 | ${{steps.cmake.outputs.cmake_binary}} 95 | --build "${{github.workspace}}/dynamic_bitset/build" 96 | --config ${{matrix.build_type}} 97 | --parallel $(nproc) 98 | 99 | - name: Ccache stats 100 | run: >- 101 | ${{steps.ccache.outputs.ccache_binary}} --show-stats 102 | 103 | - name: Run tests 104 | run: >- 105 | ${{steps.cmake.outputs.ctest_binary}} 106 | --test-dir "${{github.workspace}}/dynamic_bitset/build" 107 | --output-on-failure 108 | --parallel $(nproc) 109 | -------------------------------------------------------------------------------- /.github/actions/setup_ccache/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup ccache" 2 | description: "Setup ccache" 3 | inputs: 4 | ccache_version: 5 | description: "ccache version" 6 | required: true 7 | used_env: 8 | description: "Environment used with runs-on" 9 | required: true 10 | cache_id: 11 | description: "Cache id unique to the current config" 12 | required: true 13 | outputs: 14 | ccache_binary: 15 | description: "ccache binary path" 16 | value: ${{steps.configure.outputs.ccache_binary}} 17 | runs: 18 | using: "composite" 19 | steps: 20 | - name: Cache ccache 21 | id: cache 22 | uses: actions/cache@v4 23 | with: 24 | path: ${{github.workspace}}/ccache 25 | key: ccache-${{inputs.ccache_version}}-${{inputs.used_env}} 26 | 27 | - name: Download and install ccache 28 | id: download 29 | if: ${{steps.cache.outputs.cache-hit != 'true'}} 30 | shell: cmake -P {0} 31 | run: | 32 | file(TO_CMAKE_PATH [=[${{github.workspace}}]=] workspace) 33 | message(STATUS "Using host CMake version: ${CMAKE_VERSION}") 34 | set(ccache_url "https://github.com/ccache/ccache/releases/download/v${{inputs.ccache_version}}/ccache-${{inputs.ccache_version}}.tar.gz") 35 | message(STATUS "Download from: ${ccache_url}") 36 | file(DOWNLOAD "${ccache_url}" "${workspace}/ccache.tar.gz" SHOW_PROGRESS) 37 | message(STATUS "Extract") 38 | execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf "${workspace}/ccache.tar.gz") 39 | message(STATUS "Build ccache") 40 | execute_process( 41 | COMMAND ${CMAKE_COMMAND} 42 | -S "${workspace}/ccache-${{inputs.ccache_version}}" 43 | -B "${workspace}/ccache-${{inputs.ccache_version}}/build" 44 | -D CMAKE_CONFIGURATION_TYPES=Release 45 | -D CMAKE_BUILD_TYPE=Release 46 | -D ZSTD_FROM_INTERNET=ON 47 | -D REDIS_STORAGE_BACKEND=OFF 48 | -D ENABLE_TESTING=OFF 49 | RESULT_VARIABLE result 50 | ) 51 | if(NOT result EQUAL 0) 52 | message(FATAL_ERROR "project configuration failed") 53 | endif() 54 | include(ProcessorCount) 55 | ProcessorCount(N) 56 | execute_process( 57 | COMMAND ${CMAKE_COMMAND} 58 | --build "${workspace}/ccache-${{inputs.ccache_version}}/build" 59 | --target ccache 60 | --config Release 61 | --parallel ${N} 62 | RESULT_VARIABLE result 63 | ) 64 | if(NOT result EQUAL 0) 65 | message(FATAL_ERROR "project build failed") 66 | endif() 67 | execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${workspace}/ccache") 68 | execute_process( 69 | COMMAND ${CMAKE_COMMAND} 70 | --install "${workspace}/ccache-${{inputs.ccache_version}}/build" 71 | --prefix "${workspace}/ccache" 72 | RESULT_VARIABLE result 73 | ) 74 | if(NOT result EQUAL 0) 75 | message(FATAL_ERROR "project installation failed") 76 | endif() 77 | if(NOT "${{runner.os}}" STREQUAL "Windows") 78 | execute_process(COMMAND chmod +x "${workspace}/ccache/bin/ccache") 79 | endif() 80 | 81 | - name: Configure ccache 82 | id: configure 83 | shell: cmake -P {0} 84 | run: | 85 | file(TO_CMAKE_PATH [=[${{github.workspace}}]=] workspace) 86 | file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_BASEDIR=${workspace}\n") 87 | file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_DIR=${workspace}/.ccache\n") 88 | file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_COMPRESS=true\n") 89 | file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_COMPRESSLEVEL=6\n") 90 | file(APPEND "$ENV{GITHUB_ENV}" "CCACHE_MAXSIZE=400M\n") 91 | set(ccache_binary "${workspace}/ccache/bin/ccache") 92 | message(STATUS "ccache binary: ${ccache_binary}") 93 | file(APPEND "$ENV{GITHUB_OUTPUT}" "ccache_binary=${ccache_binary}\n") 94 | execute_process(COMMAND ${ccache_binary} --zero-stats) 95 | string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) 96 | file(APPEND "$ENV{GITHUB_OUTPUT}" "timestamp=${current_date}\n") 97 | 98 | - name: Print ccache config 99 | id: print 100 | shell: cmake -P {0} 101 | run: | 102 | execute_process(COMMAND ${{steps.configure.outputs.ccache_binary}} --version) 103 | execute_process(COMMAND ${{steps.configure.outputs.ccache_binary}} --show-config) 104 | 105 | - name: Cache ccache files 106 | uses: actions/cache@v4 107 | with: 108 | path: ${{env.CCACHE_DIR}} 109 | key: ccache-cache-${{inputs.cache_id}}-${{steps.configure.outputs.timestamp}} 110 | restore-keys: | 111 | ccache-cache-${{inputs.cache_id}}- 112 | -------------------------------------------------------------------------------- /docs/header.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | $projectname: $title 11 | $title 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | $treeview 27 | $search 28 | $mathjax 29 | $darkmode 30 | 31 | $extrastylesheet 32 | 33 | 34 | 35 | 43 | 44 | 69 | 70 | 71 | 74 | 75 | 76 | 79 | 80 | 81 | 84 | 85 | 86 | 87 | 88 |
89 | 90 | 91 | 92 |
93 | 94 | 95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 110 | 111 | 112 | 113 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 |
104 |
$projectname $projectnumber 105 | 106 |
107 | 108 |
$projectbrief
109 |
114 |
$projectbrief
115 |
$searchbox
$searchbox
135 |
136 | 137 | 138 | -------------------------------------------------------------------------------- /example/src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #include 9 | 10 | #include 11 | 12 | int main() 13 | { 14 | std::cout << std::boolalpha; 15 | 16 | // declare bitset with 12 bits from a value 17 | sul::dynamic_bitset a(12, 0b0100010110111); 18 | 19 | // conversion to string with 0 and 1 20 | std::cout << "String representation (0 and 1): " << a.to_string() << std::endl; 21 | 22 | // conversion to unsigned long 23 | std::cout << "Numeric value (unsigned long): " << a.to_ulong() << std::endl; 24 | 25 | // conversion to unsigned long long 26 | std::cout << "Numeric value (unsigned long long): " << a.to_ullong() << std::endl; 27 | 28 | // remove all bits, resize to 0 29 | a.clear(); 30 | 31 | // add a bit at 1 to the end of the bitset 32 | a.push_back(true); 33 | 34 | // remove last bit if not empty 35 | a.pop_back(); 36 | 37 | // append a full block to the bitset (including the leftmost leading 0s) 38 | // in this case append 32 bits 39 | a.append(314153u); 40 | 41 | // same as above with multiple blocks 42 | a.append({112u, 5146u, 546u}); 43 | 44 | // resize the bitset, keep 12 first bits, discard others 45 | a.resize(12); 46 | 47 | // set bits 3 to 7 to 1 48 | a.set(3, 4, true); 49 | 50 | // set bit 2 to 0 51 | a.set(2, false); 52 | 53 | // set bit 1 to 1 54 | a.set(1); 55 | 56 | // set all bits to 1 57 | a.set(); 58 | 59 | // reset bits 4 to 9 to 0 60 | a.reset(4, 5); 61 | 62 | // reset bit 8 to 0 63 | a.reset(8); 64 | 65 | // reset all bits to 0 66 | a.reset(); 67 | 68 | // flip bits 5 to 8 69 | a.flip(5, 3); 70 | 71 | // flip bit 2 72 | a.flip(2); 73 | 74 | // flip all bits 75 | a.flip(); 76 | 77 | std::cout << "a = " << a << std::endl; 78 | 79 | // test the value of bit 2 80 | std::cout << "Bit 2 is on? " << a.test(2) << std::endl; 81 | 82 | // test bit 4 and set it to 0 83 | std::cout << "Bit 4 is on? " << a.test_set(4, false) << " (set it to 0)" << std::endl; 84 | std::cout << "a = " << a << std::endl; 85 | 86 | // test bit 7 and set it to 1 87 | std::cout << "Bit 7 is on? " << a.test_set(7) << " (set it to 1)" << std::endl; 88 | std::cout << "a = " << a << std::endl; 89 | 90 | // test if the bitset is empty 91 | std::cout << "Is the bitset empty? " << a.empty() << std::endl; 92 | 93 | // get bitset size 94 | std::cout << "Bitset size: " << a.size() << std::endl; 95 | 96 | // test if all bits are 1 97 | std::cout << "All bits are on? " << a.all() << std::endl; 98 | 99 | // test if there is at least one bit at 1 100 | std::cout << "Any bits are on? " << a.any() << std::endl; 101 | 102 | // test if all bits are 0 103 | std::cout << "All bits are off? " << a.none() << std::endl; 104 | 105 | // count bits to 1 106 | std::cout << "Number of bits on: " << a.count() << std::endl; 107 | 108 | // get number of blocks used by the bitset 109 | std::cout << "Number of blocks used by the bitset: " << a.num_blocks() << std::endl; 110 | 111 | // get bitset capacity 112 | std::cout << "Bitset capacity: " << a.capacity() << std::endl; 113 | 114 | // find position of the first bit to 1 115 | const size_t pos = a.find_first(); 116 | std::cout << "First bit on position: " << pos << std::endl; 117 | 118 | // find position of the next bit to 1 119 | std::cout << "Second bit on position: " << a.find_next(pos) << std::endl; 120 | 121 | // conversion to string with . and * 122 | std::cout << "String representation (. and *): " << a.to_string('.', '*') << std::endl; 123 | 124 | // conversion to string with 0 and 1 125 | std::cout << "String representation (0 and 1): " << a.to_string() << std::endl; 126 | 127 | // conversion to unsigned long 128 | std::cout << "Numeric value (unsigned long): " << a.to_ulong() << std::endl; 129 | 130 | // conversion to unsigned long long 131 | std::cout << "Numeric value (unsigned long long): " << a.to_ullong() << std::endl; 132 | 133 | // iterate on bits on 134 | std::cout << "Bits on: "; 135 | a.iterate_bits_on([](size_t bit_pos) noexcept { std::cout << bit_pos << ' '; }); 136 | std::cout << std::endl; 137 | // (it is possible to pass parameters and return a 'continue' bool) 138 | size_t bit_counter = 0; 139 | std::cout << "3 first bits on: "; 140 | a.iterate_bits_on( 141 | [&bit_counter](size_t bit_pos, size_t limit) noexcept 142 | { 143 | std::cout << bit_pos << ' '; 144 | return ++bit_counter < limit; 145 | }, 146 | 3); 147 | std::cout << std::endl; 148 | 149 | // reserve 64 bits 150 | a.reserve(64); 151 | 152 | // requests the removal of unused capacity 153 | a.shrink_to_fit(); 154 | 155 | // get allocator 156 | [[maybe_unused]] const sul::dynamic_bitset::allocator_type allocator = a.get_allocator(); 157 | 158 | // get pointer to the underlying array of blocks 159 | const uint32_t* data = a.data(); 160 | std::cout << "address of the underlying array of blocks: " << data << std::endl; 161 | 162 | // declare bitset from string 163 | sul::dynamic_bitset b("011001010101"); 164 | std::cout << "b = " << b << std::endl; 165 | 166 | // determine if a bitset is a subset of another bitset 167 | // (if it only contains bits from the other bitset) 168 | std::cout << "a is a subset of b? " << a.is_subset_of(b) << std::endl; 169 | 170 | // determine if a bitset is a proper subset of another bitset 171 | // (if it is different and only contain bits from the other bitset) 172 | std::cout << "a is a proper subset of b? " << a.is_proper_subset_of(b) << std::endl; 173 | 174 | // determine if a bitset intersect another bitset 175 | // (if they have common bits to 1) 176 | std::cout << "Does a intersect b? " << a.intersects(b) << std::endl; 177 | 178 | // operators 179 | std::cout << "~a: " << ~a << std::endl; 180 | std::cout << "a << 3: " << (a << 3) << std::endl; 181 | std::cout << "a >> 3: " << (a >> 3) << std::endl; 182 | std::cout << "a & b: " << (a & b) << std::endl; 183 | std::cout << "a | b: " << (a | b) << std::endl; 184 | std::cout << "a ^ b: " << (a ^ b) << std::endl; 185 | std::cout << "a - b: " << (a - b) << std::endl; 186 | std::cout << "a == b: " << (a == b) << std::endl; 187 | std::cout << "a < b: " << (a < b) << std::endl; 188 | 189 | // operator[] access 190 | std::cout << "a[3]: " << a[3] << std::endl; 191 | std::cout << "~a[3]: " << ~a[3] << std::endl; 192 | a[3] = false; 193 | a[3].set(); 194 | a[3].reset(); 195 | a[3].flip(); 196 | a[3].assign(true); 197 | a[3] = a[2]; 198 | a[3] &= a[2]; 199 | a[3] |= a[2]; 200 | a[3] ^= a[2]; 201 | a[3] -= a[2]; 202 | 203 | return 0; 204 | } 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dynamic_bitset 2 | 3 | [![Ubuntu](https://github.com/pinam45/dynamic_bitset/actions/workflows/ubuntu.yml/badge.svg?branch=master)](https://github.com/pinam45/dynamic_bitset/actions/workflows/ubuntu.yml) 4 | [![Windows MSYS2](https://github.com/pinam45/dynamic_bitset/actions/workflows/windows-msys2.yml/badge.svg?branch=master)](https://github.com/pinam45/dynamic_bitset/actions/workflows/windows-msys2.yml) 5 | [![Windows Visual Studio](https://github.com/pinam45/dynamic_bitset/actions/workflows/windows-msvc.yml/badge.svg?branch=master)](https://github.com/pinam45/dynamic_bitset/actions/workflows/windows-msvc.yml) 6 | [![macOS](https://github.com/pinam45/dynamic_bitset/actions/workflows/macos.yml/badge.svg?branch=master)](https://github.com/pinam45/dynamic_bitset/actions/workflows/macos.yml) 7 | [![documentation](https://github.com/pinam45/dynamic_bitset/actions/workflows/documentation.yml/badge.svg?branch=master)](https://pinam45.github.io/dynamic_bitset) 8 | [![codecov](https://codecov.io/gh/pinam45/dynamic_bitset/branch/master/graph/badge.svg)](https://codecov.io/gh/pinam45/dynamic_bitset) 9 | [![license](https://img.shields.io/github/license/pinam45/dynamic_bitset.svg)](http://opensource.org/licenses/MIT) 10 | 11 | Simple Useful Libraries: C++17/20 header-only dynamic bitset 12 | 13 | ## Requirements 14 | 15 | To use this *dynamic bitset*, you will need a **C++17 (or later) compliant compiler**. If you use CMake and want to use the *dynamic bitset* as a subproject, you will need **CMake 3.10 or later**. 16 | 17 | ## Usage sample 18 | 19 | ```cpp 20 | #include 21 | #include 22 | #include 23 | 24 | int main() 25 | { 26 | // predefined bitset 27 | sul::dynamic_bitset<> bitset1(12, 0b0100010110111); 28 | std::cout << "bitset1 = " << bitset1 << std::endl; 29 | 30 | // random bitset 31 | std::minstd_rand rand(std::random_device{}()); 32 | std::bernoulli_distribution dist; 33 | sul::dynamic_bitset<> bitset2; 34 | for(size_t i = 0; i < 12; ++i) 35 | { 36 | bitset2.push_back(dist(rand)); 37 | } 38 | std::cout << "bitset2 = " << bitset2 << std::endl; 39 | 40 | std::cout << "common bits = " << (bitset1 & bitset2) << std::endl; 41 | return 0; 42 | } 43 | ``` 44 | 45 | Possible output: 46 | 47 | bitset1 = 100010110111 48 | bitset2 = 001011011011 49 | common bits = 000010010011 50 | 51 | Test it on [godbolt.org](https://godbolt.org/z/1veE71rYT). 52 | 53 | ## Optional dependency 54 | 55 | Optionally, [libpopcnt](https://github.com/kimwalisch/libpopcnt) will be used to optimize the bits counting operations, if the header is available (``__has_include()``) and ``DYNAMIC_BITSET_NO_LIBPOPCNT`` is not defined. 56 | 57 | ## Integration 58 | 59 | As it is a header-only library, the easiest way to integrate the *sul::dynamic_bitset* class in your project is to just copy the [sul](include/sul) folder in your project sources. Optionally, if you also copy *libpopcnt.h* from [libpopcnt](https://github.com/kimwalisch/libpopcnt), it will be used by default if it is available. 60 | 61 | ## CMake integration 62 | 63 | If you use CMake and want to use the *dynamic bitset* as a subproject, clone the repository (or add it as a git submodule) in a sub-folder of your project. Then, in your *CMakeLists.txt* add: 64 | ```CMake 65 | add_subdirectory() 66 | ``` 67 | It will define the *dynamic_bitset* target and the alias target *sul::dynamic_bitset* that you can use to add the folder containing *dynamic_bitset.hpp* to your project header folders. To do so, in your *CMakeLists.txt* add: 68 | ```CMake 69 | target_link_libraries( PRIVATE sul::dynamic_bitset) 70 | ``` 71 | 72 | For example, a simple project with the repository as a git submodule in the *extlibs* folder, could have a *CMakeLists.txt* similar to this: 73 | ```CMake 74 | cmake_minimum_required(VERSION 3.10) 75 | project(CoolProject LANGUAGES CXX) 76 | 77 | add_executable(CoolProject main.cpp) 78 | target_compile_features(CoolProject PRIVATE cxx_std_20) 79 | 80 | add_subdirectory(extlibs/dynamic_bitset) 81 | target_link_libraries(CoolProject PRIVATE sul::dynamic_bitset) 82 | ``` 83 | 84 | If you pulled the git submodule libpopcnt (in [extlibs](extlibs)) and set the *dynamic bitset* CMake options ``DYNAMICBITSET_USE_LIBPOPCNT`` and ``DYNAMICBITSET_USE_LIBPOPCNT_SUBMODULE`` to ``ON``(default values), the folder containing *libpopcnt.h* will also be added to the headers paths and libpopcnt will be used. 85 | 86 | ## CMake options 87 | 88 | ### Descriptions 89 | 90 | - ``DYNAMICBITSET_NO_NAMESPACE``: Put the dynamic_bitset class in the global namespace instead of the sul namespace (not recommended) 91 | - ``DYNAMICBITSET_USE_LIBPOPCNT``: Enable using libpopcnt for bits counting operations 92 | - ``DYNAMICBITSET_USE_LIBPOPCNT_SUBMODULE``: Enable adding libpopcnt submodule to include paths (disable if your project already include libpopcnt) 93 | - ``DYNAMICBITSET_USE_STD_BITOPS``: Enable using (if available) C++20 binary operations from the bit header 94 | - ``DYNAMICBITSET_USE_COMPILER_BUILTIN``: Enable using (if available) compiler builtins (if using C++20 binary operations is disabled or not possible) 95 | - ``DYNAMICBITSET_BUILD_EXAMPLE``: Enable building example for dynamic_bitset 96 | - ``DYNAMICBITSET_BUILD_TESTS``: Enable building tests for dynamic_bitset 97 | - ``DYNAMICBITSET_BUILD_DOCS``: Enable building documentation for dynamic_bitset 98 | - ``DYNAMICBITSET_FORMAT_TARGET``: Enable generating a code formating target for dynamic_bitset 99 | - ``DYNAMICBITSET_HEADERS_TARGET_IDE``: Enable generating a target with headers for ide for dynamic_bitset 100 | 101 | ### Default values 102 | 103 | | Option | Default value as top level project | Default value as subdirectory | 104 | | ------------------------------------- | :--------------------------------: | :---------------------------: | 105 | | DYNAMICBITSET_NO_NAMESPACE | OFF | OFF | 106 | | DYNAMICBITSET_USE_LIBPOPCNT | ON | ON | 107 | | DYNAMICBITSET_USE_LIBPOPCNT_SUBMODULE | ON | ON | 108 | | DYNAMICBITSET_USE_STD_BITOPS | ON | ON | 109 | | DYNAMICBITSET_USE_COMPILER_BUILTIN | ON | ON | 110 | | DYNAMICBITSET_BUILD_EXAMPLE | ON | OFF | 111 | | DYNAMICBITSET_BUILD_TESTS | ON | OFF | 112 | | DYNAMICBITSET_BUILD_DOCS | ON | OFF | 113 | | DYNAMICBITSET_FORMAT_TARGET | ON | OFF | 114 | | DYNAMICBITSET_HEADERS_TARGET_IDE | ON | OFF | 115 | 116 | ## Build tests, example, and documentation 117 | 118 | > [!NOTE] 119 | > The latest version of the documentation is available online [here](https://pinam45.github.io/dynamic_bitset). 120 | 121 | To build the tests, the example, and the documentation, git submodules are required, so don't forget to pull the submodules with the repository using ``--recursive``: 122 | 123 | $ git clone --recursive https://github.com/pinam45/dynamic_bitset.git 124 | 125 | or if you have already cloned the repository: 126 | 127 | $ git submodule update --init --recursive 128 | 129 | The project uses CMake to build and define the options ``DYNAMICBITSET_BUILD_TESTS``, ``DYNAMICBITSET_BUILD_EXAMPLE``, and ``DYNAMICBITSET_BUILD_DOCS`` to enable the generation of the tests, example, and documentation targets, these option are enabled by default if the project is the master project (not included from another *CMakeLists.txt* with *add_subdirectory*). 130 | 131 | Generating the documentation requires **[Doxygen](http://www.doxygen.nl/) 1.9.6 or later** and is done by building the target *dynamic_bitset_docs*. For running the tests, build the *dynamic_bitset_tests* target and launch the tests using ctest. 132 | 133 | See [Running CMake](https://cmake.org/runningcmake/) and [the ctest documentation](https://cmake.org/cmake/help/latest/manual/ctest.1.html) for more information. On linux, a common way of doing this is: 134 | 135 | $ mkdir cmake-build 136 | $ cd cmake-build 137 | $ cmake .. 138 | $ cmake --build . 139 | $ ctest --output-on-failure 140 | 141 | On Windows, there is batch files available to configure a Visual Studio project in the [ide](ide) folder. 142 | 143 | ## License 144 | 145 | dynamic_bitset is licensed under the [MIT License](http://opensource.org/licenses/MIT): 146 | 147 | Copyright © 2019 [Maxime Pinard](https://github.com/pinam45) 148 | 149 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 150 | 151 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 152 | 153 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 154 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) # For ARCH_INDEPENDENT in write_basic_package_version_file 2 | 3 | # Project declaration 4 | project( 5 | dynamic_bitset 6 | VERSION 1.3.2 7 | DESCRIPTION "Simple Useful Libraries: C++17/20 header-only dynamic bitset" 8 | HOMEPAGE_URL "https://github.com/pinam45/dynamic_bitset" 9 | LANGUAGES CXX 10 | ) 11 | 12 | # Check if dynamic_bitset is being used directly or via add_subdirectory 13 | get_directory_property(HAS_PARENT PARENT_DIRECTORY) 14 | if(HAS_PARENT) 15 | set(DYNAMICBITSET_TOPLEVEL_PROJECT OFF) 16 | else() 17 | set(DYNAMICBITSET_TOPLEVEL_PROJECT ON) 18 | endif() 19 | 20 | # Options 21 | include(CMakeDependentOption) 22 | option( 23 | DYNAMICBITSET_NO_NAMESPACE 24 | "Put the dynamic_bitset class in the global namespace instead of the sul namespace (not recommended)" 25 | OFF 26 | ) 27 | option( 28 | DYNAMICBITSET_USE_LIBPOPCNT 29 | "Enable using (if available) libpopcnt for bits counting operations" 30 | ON 31 | ) 32 | cmake_dependent_option( 33 | DYNAMICBITSET_USE_LIBPOPCNT_SUBMODULE 34 | "Enable adding libpopcnt submodule to include paths (disable if your project already include libpopcnt)" 35 | ON 36 | "DYNAMICBITSET_USE_LIBPOPCNT" 37 | OFF 38 | ) 39 | option( 40 | DYNAMICBITSET_USE_STD_BITOPS 41 | "Enable using (if available) C++20 binary operations from the bit header" 42 | ON 43 | ) 44 | option( 45 | DYNAMICBITSET_USE_COMPILER_BUILTIN 46 | "Enable using (if available) compiler builtins (if using C++20 binary operations is disabled or not possible)" 47 | ON 48 | ) 49 | option( 50 | DYNAMICBITSET_BUILD_EXAMPLE 51 | "Enable building example for dynamic_bitset" 52 | ${DYNAMICBITSET_TOPLEVEL_PROJECT} 53 | ) 54 | option( 55 | DYNAMICBITSET_BUILD_TESTS 56 | "Enable building tests for dynamic_bitset" 57 | ${DYNAMICBITSET_TOPLEVEL_PROJECT} 58 | ) 59 | option( 60 | DYNAMICBITSET_BUILD_DOCS 61 | "Enable building documentation for dynamic_bitset" 62 | ${DYNAMICBITSET_TOPLEVEL_PROJECT} 63 | ) 64 | option( 65 | DYNAMICBITSET_FORMAT_TARGET 66 | "Enable generating a code formating target for dynamic_bitset" 67 | ${DYNAMICBITSET_TOPLEVEL_PROJECT} 68 | ) 69 | option( 70 | DYNAMICBITSET_HEADERS_TARGET_IDE 71 | "Enable generating a target with headers for ide for dynamic_bitset" 72 | ${DYNAMICBITSET_TOPLEVEL_PROJECT} 73 | ) 74 | option( 75 | DYNAMICBITSET_INSTALL 76 | "Enable installation for dynamic_bitset" 77 | ${DYNAMICBITSET_TOPLEVEL_PROJECT} 78 | ) 79 | cmake_dependent_option( 80 | DYNAMICBITSET_INSTALL_LIBPOPCNT_SUBMODULE 81 | "When installing dynamic_bitset, also install libpopcnt from submodule (if available)" 82 | ${DYNAMICBITSET_TOPLEVEL_PROJECT} 83 | "DYNAMICBITSET_INSTALL;DYNAMICBITSET_USE_LIBPOPCNT;DYNAMICBITSET_USE_LIBPOPCNT_SUBMODULE" 84 | OFF 85 | ) 86 | 87 | # Declare dynamic_bitset 88 | add_library(dynamic_bitset INTERFACE) 89 | add_library(sul::dynamic_bitset ALIAS dynamic_bitset) 90 | 91 | # If used via add_subdirectory, disable warnings on headers 92 | set(MAYBE_SYSTEM) 93 | if(NOT DYNAMICBITSET_TOPLEVEL_PROJECT) 94 | set(MAYBE_SYSTEM SYSTEM) 95 | endif() 96 | 97 | # Add includes 98 | target_include_directories( 99 | dynamic_bitset ${MAYBE_SYSTEM} INTERFACE 100 | "$" 101 | "$" 102 | ) 103 | 104 | # Put the dynamic_bitset class in the global namespace? 105 | if(DYNAMICBITSET_NO_NAMESPACE) 106 | target_compile_definitions(dynamic_bitset INTERFACE DYNAMIC_BITSET_NO_NAMESPACE) 107 | endif() 108 | 109 | # Set minimum required standard 110 | target_compile_features(dynamic_bitset INTERFACE cxx_std_17) 111 | 112 | # Use libpopcnt? 113 | if(DYNAMICBITSET_USE_LIBPOPCNT) 114 | message(STATUS "dynamic_bitset: libpopcnt usage enabled") 115 | 116 | # Use the submodule of the git repository? 117 | if(DYNAMICBITSET_USE_LIBPOPCNT_SUBMODULE) 118 | get_filename_component(LIBPOPCNT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/extlibs/libpopcnt/libpopcnt.h" ABSOLUTE) 119 | if(EXISTS "${LIBPOPCNT_PATH}") 120 | message(STATUS "dynamic_bitset: libpopcnt submodule is present and will be used") 121 | target_include_directories( 122 | dynamic_bitset SYSTEM INTERFACE 123 | "$" 124 | ) 125 | else() 126 | message(WARNING "dynamic_bitset: libpopcnt submodule is missing and won't be used, maybe you didn't pull the git submodules") 127 | set(DYNAMICBITSET_USE_LIBPOPCNT_SUBMODULE OFF) 128 | endif() 129 | else() 130 | message(STATUS "dynamic_bitset: libpopcnt submodule won't be used") 131 | endif() 132 | else() 133 | target_compile_definitions(dynamic_bitset INTERFACE DYNAMIC_BITSET_NO_LIBPOPCNT) 134 | message(STATUS "dynamic_bitset: libpopcnt usage disabled") 135 | endif() 136 | 137 | # Use C++20 binary operations? 138 | if(DYNAMICBITSET_USE_STD_BITOPS) 139 | message(STATUS "dynamic_bitset: C++20 binary operations usage enabled") 140 | else() 141 | target_compile_definitions(dynamic_bitset INTERFACE DYNAMIC_BITSET_NO_STD_BITOPS) 142 | message(STATUS "dynamic_bitset: C++20 binary operations usage disabled") 143 | endif() 144 | 145 | # Use compiler builtins? 146 | if(DYNAMICBITSET_USE_COMPILER_BUILTIN) 147 | message(STATUS "dynamic_bitset: compiler builtins usage enabled") 148 | else() 149 | target_compile_definitions(dynamic_bitset INTERFACE DYNAMIC_BITSET_NO_COMPILER_BUILTIN) 150 | message(STATUS "dynamic_bitset: compiler builtins usage disabled") 151 | endif() 152 | 153 | # Global config if top level project 154 | if(DYNAMICBITSET_TOPLEVEL_PROJECT) 155 | # Disable sources modifications 156 | set(CMAKE_DISABLE_SOURCE_CHANGES ON) 157 | set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 158 | 159 | # Strict C++ standard 160 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 161 | set(CMAKE_CXX_EXTENSIONS OFF) 162 | 163 | # IDE folders 164 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 165 | set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "_CMake") 166 | 167 | # Flags 168 | include(cmake/flags.cmake) 169 | endif() 170 | 171 | # Create Headers target for IDE? 172 | if(DYNAMICBITSET_HEADERS_TARGET_IDE) 173 | add_custom_target(dynamic_bitset_headers_for_ide SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/include/sul/dynamic_bitset.hpp") 174 | source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/sul/dynamic_bitset.hpp") 175 | set_target_properties(dynamic_bitset_headers_for_ide PROPERTIES FOLDER "dynamic_bitset") 176 | endif() 177 | 178 | # Generate format target? 179 | if(DYNAMICBITSET_FORMAT_TARGET) 180 | find_program(CLANG_FORMAT clang-format) 181 | if(${CLANG_FORMAT} STREQUAL CLANG_FORMAT-NOTFOUND) 182 | message(WARNING "clang-format not found, format targets not generated") 183 | set(DYNAMICBITSET_FORMAT_TARGET OFF) 184 | else() 185 | message(STATUS "clang-format found: ${CLANG_FORMAT}") 186 | add_custom_target( 187 | format-dynamic_bitset 188 | COMMAND "${CLANG_FORMAT}" -style=file -i "${CMAKE_CURRENT_SOURCE_DIR}/include/sul/dynamic_bitset.hpp" 189 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 190 | VERBATIM 191 | ) 192 | set_target_properties(format-dynamic_bitset PROPERTIES FOLDER "dynamic_bitset/format") 193 | endif() 194 | endif() 195 | 196 | # Build example? 197 | if(DYNAMICBITSET_BUILD_EXAMPLE) 198 | add_subdirectory(example) 199 | 200 | # Set example as startup project for Visual Studio 201 | set_property( 202 | DIRECTORY 203 | ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY 204 | VS_STARTUP_PROJECT dynamic_bitset_example 205 | ) 206 | endif() 207 | 208 | # Build tests? 209 | if(DYNAMICBITSET_BUILD_TESTS) 210 | enable_testing() 211 | 212 | # Catch2 213 | get_filename_component(CATCH2_CMAKELISTS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/extlibs/Catch2/CMakeLists.txt" ABSOLUTE) 214 | if(NOT EXISTS "${CATCH2_CMAKELISTS_PATH}") 215 | message(FATAL_ERROR "Catch2 dependency is missing, maybe you didn't pull the git submodules") 216 | endif() 217 | if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.25) 218 | add_subdirectory(extlibs/Catch2 SYSTEM) 219 | else() 220 | add_subdirectory(extlibs/Catch2) 221 | endif() 222 | include(extlibs/Catch2/extras/Catch.cmake) 223 | 224 | # Disable warnings on Catch2 headers 225 | get_target_property(Catch2_include_directories Catch2 INTERFACE_INCLUDE_DIRECTORIES) 226 | set_target_properties(Catch2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "") 227 | target_include_directories(Catch2 SYSTEM INTERFACE ${Catch2_include_directories}) 228 | 229 | # Tests 230 | add_subdirectory(tests) 231 | endif() 232 | 233 | # Build documentation? 234 | if(DYNAMICBITSET_BUILD_DOCS) 235 | add_subdirectory(docs) 236 | endif() 237 | 238 | # Install the cmake 239 | if(DYNAMICBITSET_INSTALL) 240 | include(GNUInstallDirs) 241 | include(CMakePackageConfigHelpers) 242 | install( 243 | TARGETS dynamic_bitset 244 | EXPORT sul 245 | ) 246 | # do not use PUBLIC_HEADER property, it flatten include sub-folder, directly install includes 247 | install( 248 | DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 249 | ) 250 | if(DYNAMICBITSET_INSTALL_LIBPOPCNT_SUBMODULE) 251 | get_filename_component(LIBPOPCNT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/extlibs/libpopcnt/libpopcnt.h" ABSOLUTE) 252 | if(EXISTS "${LIBPOPCNT_PATH}") 253 | install( 254 | FILES "${LIBPOPCNT_PATH}" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 255 | ) 256 | else() 257 | message(WARNING "dynamic_bitset: libpopcnt submodule is missing and can't be part of the install, maybe you didn't pull the git submodules") 258 | endif() 259 | endif() 260 | install( 261 | EXPORT sul 262 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sul-dynamic_bitset 263 | NAMESPACE sul:: 264 | FILE sul-dynamic_bitset.cmake 265 | ) 266 | install( 267 | FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/sul-dynamic_bitset-config.cmake 268 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sul-dynamic_bitset 269 | ) 270 | write_basic_package_version_file( 271 | ${CMAKE_CURRENT_BINARY_DIR}/sul-dynamic_bitset-config-version.cmake 272 | COMPATIBILITY SameMajorVersion 273 | ARCH_INDEPENDENT 274 | ) 275 | install( 276 | FILES ${CMAKE_CURRENT_BINARY_DIR}/sul-dynamic_bitset-config-version.cmake 277 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sul-dynamic_bitset 278 | ) 279 | endif() 280 | -------------------------------------------------------------------------------- /cmake/flags.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2022 Maxime Pinard 3 | # 4 | # Distributed under the MIT license 5 | # See accompanying file LICENSE or copy at 6 | # https://opensource.org/licenses/MIT 7 | # 8 | cmake_minimum_required(VERSION 3.18) # For check_linker_flag 9 | 10 | message(CHECK_START "Compiler flags configuration") 11 | list(APPEND CMAKE_MESSAGE_INDENT " ") 12 | 13 | # MSVC debug flags 14 | set(MSVC_DEBUG_FLAGS 15 | /utf-8 # Set source and execution character sets to UTF-8. 16 | /validate-charset # Validate UTF-8 files for only compatible characters. 17 | # /analyse # Enables code analysis. 18 | /diagnostics:caret # Diagnostics format: prints column and the indicated line of source. 19 | /W4 # Warning level 20 | /sdl # Enable Additional Security Checks 21 | # https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default 22 | # /w44061 # enumerator 'identifier' in a switch of enum 'enumeration' is not explicitly handled by a case label 23 | # /w44062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled 24 | # /w14165 # 'HRESULT' is being converted to 'bool'; are you sure this is what you want? 25 | # /w34191 # 'operator': unsafe conversion from 'type_of_expression' to 'type_required' 26 | # /w44242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data 27 | # /w44254 # 'operator': conversion from 'type1' to 'type2', possible loss of data 28 | # /w44255 # 'function': no function prototype given: converting '()' to '(void)' 29 | /w44263 # 'function': member function does not override any base class virtual member function 30 | /w14264 # 'virtual_function': no override available for virtual member function from base 'class'; function is hidden 31 | /w34265 # 'class': class has virtual functions, but destructor is not virtual 32 | # /w44266 # 'function': no override available for virtual member function from base 'type'; function is hidden 33 | /w34287 # 'operator': unsigned/negative constant mismatch 34 | /w44289 # nonstandard extension used : 'var' : loop control variable declared in the for-loop is used outside the for-loop scope 35 | /w44296 # 'operator': expression is always false 36 | # /w44339 # 'type' : use of undefined type detected in CLR meta-data - use of this type may lead to a runtime exception 37 | # /w14342 # behavior change: 'function' called, but a member operator was called in previous versions 38 | # /w14350 # behavior change: 'member1' called instead of 'member2' 39 | /w44355 # 'this' : used in base member initializer list 40 | /w44365 # 'action': conversion from 'type_1' to 'type_2', signed/unsigned mismatch 41 | # /w34370 # layout of class has changed from a previous version of the compiler due to better packing 42 | # /w34371 # 'classname': layout of class may have changed from a previous version of the compiler due to better packing of member 'member' 43 | # /w44388 # signed/unsigned mismatch 44 | /w24412 # 'function': function signature contains type 'type'; C++ objects are unsafe to pass between pure code and mixed or native 45 | # /w14426 # optimization flags changed after including header, may be due to #pragma optimize() 14.1 46 | # /w44435 # 'class1' : Object layout under /vd2 will change due to virtual base 'class2' 47 | # /w44437 # dynamic_cast from virtual base 'class1' to 'class2' could fail in some contexts 48 | # /w34444 # top level '__unaligned' is not implemented in this context 49 | /w44464 # relative include path contains '..' 50 | # /w44471 # a forward declaration of an unscoped enumeration must have an underlying type (int assumed) Perm 51 | # /w14472 # 'identifier' is a native enum: add an access specifier (private/public) to declare a managed enum 52 | # /w44514 # 'function': unreferenced inline function has been removed 53 | # /w44536 # 'type name': type-name exceeds meta-data limit of 'limit' characters 54 | /w14545 # expression before comma evaluates to a function which is missing an argument list 55 | /w14546 # function call before comma missing argument list 56 | /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect 57 | /w14548 # expression before comma has no effect; expected expression with side-effect 58 | /w14549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? 59 | /w14555 # expression has no effect; expected expression with side-effect 60 | /w34557 # '__assume' contains effect 'effect' 61 | # /w44571 # informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught 62 | # /w44574 # 'identifier' is defined to be '0': did you mean to use '#if identifier'? 63 | # /w14577 # 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc 64 | # /w44582 # 'type': constructor is not implicitly called 65 | # /w44583 # 'type': destructor is not implicitly called 66 | # /w14587 # 'anonymous_structure': behavior change: constructor is no longer implicitly called 67 | # /w14588 # 'anonymous_structure': behavior change: destructor is no longer implicitly called 68 | /w44596 # 'identifier': illegal qualified name in member declaration 14.3 Perm 69 | # /w33598 # '#include "header"': header number header-number in the precompiled header does not match current compilation at that position 14.3 70 | # /w34599 # 'option path': command-line argument number number does not match pre-compiled header 14.3 71 | # /w14605 # '/Dmacro' specified on current command line, but was not specified when precompiled header was built 72 | /w34608 # 'union_member' has already been initialized by another union member in the initializer list, 'union_member' Perm 73 | # /w34619 # #pragma warning: there is no warning number 'number' 74 | # /w44623 # 'derived class': default constructor could not be generated because a base class default constructor is inaccessible 75 | # /w44625 # 'derived class': copy constructor could not be generated because a base class copy constructor is inaccessible 76 | # /w44626 # 'derived class': assignment operator could not be generated because a base class assignment operator is inaccessible 77 | /w14628 # digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char' 78 | # /w34640 # 'instance': construction of local static object is not thread-safe 79 | /w44643 # Forward declaring 'identifier' in namespace std is not permitted by the C++ Standard. 15.8 80 | # /w34647 # behavior change: __is_pod(type) has different value in previous versions 81 | /w44654 # Code placed before include of precompiled header line will be ignored. Add code to precompiled header. 14.1 82 | /w44668 # 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' 83 | # /w44682 # 'symbol' : no directional parameter attribute specified, defaulting to [in] 84 | # /w34686 # 'user-defined type': possible change in behavior, change in UDT return calling convention 85 | # /w14692 # 'function': signature of non-private member contains assembly private native type 'native_type' 86 | # /w44710 # 'function': function not inlined 87 | # /w34738 # storing 32-bit float result in memory, possible loss of performance 88 | # /w44746 # volatile access of 'expression' is subject to /volatile: setting; consider using __iso_volatile_load/store intrinsic functions 89 | # /w44749 # conditionally supported: offsetof applied to non-standard-layout type 'type' 90 | # /w44767 # section name 'symbol' is longer than 8 characters and will be truncated by the linker 91 | # /w44774 # 'string' : format string expected in argument number is not a string literal 92 | /w44777 # 'function' : format string 'string' requires an argument of type 'type1', but variadic argument number has type 'type2' 93 | # /w34786 # 'symbol' : object name was truncated to 'number' characters in the debug information 94 | # /w44800 # Implicit conversion from 'type' to bool. Possible information loss 16.0 95 | # /w44820 # 'bytes' bytes padding added after construct 'member_name' 96 | /w14822 # 'member': local class member function does not have a body 97 | # /w24826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior. 98 | /w44837 # trigraph detected: '??character' replaced by 'character' 99 | /w44841 # non-standard extension used: compound member designator used in offsetof 100 | # /w44842 # the result of 'offsetof' applied to a type using multiple inheritance is not guaranteed to be consistent between compiler releases 101 | # /w44866 # 'file(line-number)' compiler may not enforce left-to-right evaluation order for call to operator 102 | # /w44868 # 'file(line_number)' compiler may not enforce left-to-right evaluation order in braced initialization list 103 | # /w14905 # wide string literal cast to 'LPSTR' 104 | # /w14906 # string literal cast to 'LPWSTR' 105 | /w14917 # 'declarator': a GUID can only be associated with a class, interface, or namespace 106 | /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied 107 | # /w44931 # we are assuming the type library was built for number-bit pointers 108 | /w14946 # reinterpret_cast used between related classes: 'class1' and 'class2' 109 | # /w44962 # 'function': profile-guided optimizations disabled because optimizations caused profile data to become inconsistent 110 | /w44986 # 'symbol': exception specification does not match previous declaration 111 | /w44987 # nonstandard extension used: 'throw (...)' 112 | # /w44988 # 'symbol': variable declared outside class/function scope 113 | # /w45022 # 'type': multiple move constructors specified 114 | # /w45023 # 'type': multiple move assignment operators specified 115 | # /w45024 # 'type': move constructor was implicitly defined as deleted 116 | # /w45025 # 'type': move assignment operator was implicitly defined as deleted 117 | # /w45026 # 'type': move constructor was implicitly defined as deleted 118 | # /w45027 # 'type': move assignment operator was implicitly defined as deleted 119 | /w45029 # nonstandard extension used: alignment attributes in C++ apply to variables, data members and tag types only 120 | /w45031 # #pragma warning(pop): likely mismatch, popping warning state pushed in different file 14.1 121 | /w45032 # detected #pragma warning(push) with no corresponding #pragma warning(pop) 14.1 122 | # /w45034 # use of intrinsic 'intrinsic' causes function function-name to be compiled as guest code 15.3 123 | # /w45035 # use of feature 'feature' causes function function-name to be compiled as guest code 15.3 124 | # /w15036 # varargs function pointer conversion when compiling with /hybrid:x86arm64 'type1' to 'type2' 15.3 125 | /w45038 # data member 'member1' will be initialized after data member 'member2' 15.3 126 | # /w45039 # 'function': pointer or reference to potentially throwing function passed to extern C function under -EHc. Undefined behavior may occur if this function throws an exception. 15.5 127 | /w45041 # 'member-name': out-of-line definition for constexpr static data member is not needed and is deprecated in C++17. 15.2 128 | /w35042 # 'function': function declarations at block scope cannot be specified 'inline' in standard C++; remove 'inline' specifier 15.5 129 | # /w45045 # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified 15.7 130 | # /w35052 # Keyword 'keyword-name' was introduced in C++version and requires use of the 'option' command-line option` 16.1 131 | /w35204 # A class with virtual functions has non-virtual trivial destructor. 16.5 132 | /w45214 # applying 'keyword' to an operand with a volatile qualified type is deprecated in C++20 16.7 133 | /w45215 # 'function-parameter' a function parameter with a volatile qualified type is deprecated in C++20 16.7 134 | /w45216 # 'return-type' a volatile qualified return type is deprecated in C++20 16.7 135 | /w45217 # a structured binding declaration that includes volatile is deprecated in C++20 16.7 136 | # /w25219 # implicit conversion from 'type-1' to 'type-2', possible loss of data 16.7 137 | # /w45220 # 'member': a non-static data member with a volatile qualified type no longer implies that compiler generated copy/move constructors and copy/move assignment operators are not trivial 16.7 138 | /w45233 # explicit lambda capture 'identifier' is not used 16.10 139 | /w45240 # 'attribute-name': attribute is ignored in this syntactic position 16.10 140 | /w15243 # 'type-name': using incomplete class 'class-name' can cause potential one definition rule violation due to ABI limitation 16.10 141 | # /w45245 # 'function': unreferenced function with internal linkage has been removed 142 | /w15246 # 'member': the initialization of a subobject should be wrapped in braces 16.10 143 | /w15247 # Section 'section-name' is reserved for C++ dynamic initialization. Manually creating the section will interfere with C++ dynamic initialization and may lead to undefined behavior 16.11 144 | /w15248 # Section 'section-name' is reserved for C++ dynamic initialization. Variable manually put into the section may be optimized out and its order relative to compiler generated dynamic initializers is unspecified 16.11 145 | /w15249 # 'bitfield' of type 'enumeration_name' has named enumerators with values that cannot be represented in the given bit field width of 'bitfield_width'. 17.0 146 | /w35250 # 'function_name': intrinsic function not declared. 17.0 147 | # /w45251 # segment-name changed after including header 17.1 148 | # /w45254 # language feature 'terse static assert' requires compiler flag '/std:c++17' 17.1 149 | 150 | ## Explicitly disabled warnings 151 | /wd4702 # unreachable code 152 | ) 153 | 154 | # GCC debug flags 155 | set(GCC_DEBUG_FLAGS 156 | # General: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html 157 | -Wfatal-errors 158 | # -fanalyzer 159 | -Wlifetime 160 | -pedantic 161 | -pedantic-errors 162 | -Wall 163 | -Wextra 164 | -Wdouble-promotion 165 | -Wformat=2 166 | -Wformat-signedness 167 | -Wnull-dereference 168 | -Wimplicit-fallthrough 169 | -Wif-not-aligned 170 | -Wmissing-include-dirs 171 | # -Wswitch-default 172 | # -Wswitch-enum 173 | -Wswitch-bool 174 | -Wswitch-unreachable 175 | # -Wunused-parameter 176 | -Wuninitialized 177 | -Wstrict-overflow=5 178 | -Walloc-zero 179 | -Wduplicated-branches 180 | -Wduplicated-cond 181 | -Wfloat-equal 182 | -Wshadow 183 | -Wundef 184 | -Wcast-qual 185 | -Wcast-align 186 | -Wconversion 187 | -Wsign-conversion 188 | -Wdate-time 189 | -Wlogical-op 190 | -Wmissing-declarations 191 | -Wredundant-decls 192 | -Wrestrict 193 | -Winterference-size 194 | -Winvalid-pch 195 | -Wvla 196 | -Woverlength-strings 197 | # C++ specific: https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html 198 | -Wcomma-subscript 199 | -Wctad-maybe-unsupported 200 | -Wctor-dtor-privacy 201 | -Wnoexcept 202 | -Wnon-virtual-dtor 203 | -Wregister 204 | -Wredundant-tags 205 | -Wstrict-null-sentinel 206 | -Wold-style-cast 207 | # -Woverloaded-virtual 208 | -Wmismatched-tags 209 | -Wvolatile 210 | -Wzero-as-null-pointer-constant 211 | -Wextra-semi 212 | # -Wuseless-cast 213 | -Wsubobject-linkage 214 | -Wdelete-incomplete 215 | # Suggest 216 | -Weffc++ 217 | -Wsuggest-override 218 | #-Wsuggest-final-types 219 | #-Wsuggest-final-methods 220 | #-Wsuggest-attribute=pure 221 | #-Wsuggest-attribute=const 222 | #-Wsuggest-attribute=noreturn 223 | #-Wsuggest-attribute=format 224 | ) 225 | 226 | # CLANG debug flags 227 | set(CLANG_DEBUG_FLAGS 228 | # https://clang.llvm.org/docs/DiagnosticsReference.html 229 | -Wfatal-errors 230 | -Wlifetime 231 | -pedantic 232 | -pedantic-errors 233 | -Wall 234 | -Wextra 235 | -Wbad-function-cast 236 | -Wcomma 237 | -Wcomment 238 | -Wcomplex-component-init 239 | -Wconditional-uninitialized 240 | -Wcovered-switch-default 241 | -Wcstring-format-directive 242 | -Wdelete-non-virtual-dtor 243 | -Wdeprecated 244 | -Wdollar-in-identifier-extension 245 | -Wdouble-promotion 246 | -Wduplicate-enum 247 | -Wduplicate-method-arg 248 | -Wembedded-directive 249 | -Wexpansion-to-defined 250 | -Wfloat-conversion 251 | -Wfloat-equal 252 | -Wfor-loop-analysis 253 | -Wformat-pedantic 254 | -Wgnu 255 | -Wimplicit-fallthrough 256 | -Winfinite-recursion 257 | -Winvalid-or-nonexistent-directory 258 | -Wkeyword-macro 259 | -Wmain 260 | -Wmethod-signatures 261 | -Wmicrosoft 262 | -Wmismatched-tags 263 | -Wmissing-field-initializers 264 | -Wmissing-method-return-type 265 | -Wmissing-prototypes 266 | -Wmissing-variable-declarations 267 | -Wnested-anon-types 268 | -Wnon-virtual-dtor 269 | -Wnonportable-system-include-path 270 | -Wnull-pointer-arithmetic 271 | -Wnullability-extension 272 | -Wold-style-cast 273 | -Woverriding-method-mismatch 274 | -Wpacked 275 | -Wpedantic 276 | -Wpessimizing-move 277 | -Wredundant-move 278 | -Wreserved-id-macro 279 | -Wself-assign 280 | -Wself-move 281 | -Wsemicolon-before-method-body 282 | -Wshadow 283 | -Wshadow-field 284 | -Wshadow-field-in-constructor 285 | -Wshadow-uncaptured-local 286 | -Wshift-sign-overflow 287 | -Wshorten-64-to-32 288 | -Wconversion 289 | -Wsigned-enum-bitfield 290 | -Wstatic-in-inline 291 | -Wtautological-compare 292 | -Wtautological-overlap-compare 293 | -Wthread-safety 294 | -Wundefined-reinterpret-cast 295 | -Wuninitialized 296 | -Wunreachable-code 297 | -Wunreachable-code-aggressive 298 | -Wunused-const-variable 299 | -Wunused-lambda-capture 300 | -Wunused-local-typedef 301 | -Wunused-parameter 302 | -Wunused-private-field 303 | -Wunused-template 304 | -Wunused-variable 305 | -Wused-but-marked-unused 306 | -Wzero-as-null-pointer-constant 307 | -Wzero-length-array 308 | ) 309 | 310 | # Asan flags 311 | set(GCC_GLANG_ASAN_FLAGS 312 | -fsanitize=address 313 | -fno-omit-frame-pointer 314 | -fno-optimize-sibling-calls 315 | ) 316 | set(MSVC_ASAN_FLAGS /fsanitize=address) 317 | 318 | # UBsan flags 319 | set(GCC_GLANG_UBSAN_FLAGS 320 | -fsanitize=undefined 321 | -fsanitize=shift 322 | -fsanitize=shift-exponent 323 | -fsanitize=shift-base 324 | -fsanitize=integer-divide-by-zero 325 | -fsanitize=unreachable 326 | -fsanitize=vla-bound 327 | -fsanitize=null 328 | -fsanitize=return 329 | -fsanitize=bounds 330 | -fsanitize=bounds-strict 331 | -fsanitize=alignment 332 | -fsanitize=object-size 333 | -fsanitize=float-divide-by-zero 334 | -fsanitize=float-cast-overflow # detect floating-point division by zero which can be legitimate to get infinity and NaN 335 | -fsanitize=nonnull-attribute 336 | -fsanitize=returns-nonnull-attribute 337 | -fsanitize=bool 338 | -fsanitize=enum 339 | -fsanitize=pointer-overflow 340 | -fsanitize=builtin 341 | # -fno-sanitize=vptr # linking problems on buster 342 | ) 343 | set(MSVC_UBSAN_FLAGS) 344 | 345 | # Tsan flags 346 | set(GCC_GLANG_TSAN_FLAGS 347 | -fsanitize=thread 348 | ) 349 | set(MSVC_TSAN_FLAGS) 350 | 351 | # Identify compiler 352 | set(DEGUG_FLAGS) 353 | # https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html 354 | if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") 355 | message(STATUS "C++ compiler is MSVC-like Clang") 356 | set(DEGUG_FLAGS ${MSVC_DEBUG_FLAGS}) 357 | set(ASAN_FLAGS ${MSVC_ASAN_FLAGS}) 358 | set(UBSAN_FLAGS ${MSVC_UBSAN_FLAGS}) 359 | set(TSAN_FLAGS ${MSVC_TSAN_FLAGS}) 360 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 361 | message(STATUS "C++ compiler is Microsoft Visual Studio") 362 | set(DEGUG_FLAGS ${MSVC_DEBUG_FLAGS}) 363 | set(ASAN_FLAGS ${MSVC_ASAN_FLAGS}) 364 | set(UBSAN_FLAGS ${MSVC_UBSAN_FLAGS}) 365 | set(TSAN_FLAGS ${MSVC_TSAN_FLAGS}) 366 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 367 | message(STATUS "C++ compiler is LLVM Clang") 368 | set(DEGUG_FLAGS ${CLANG_DEBUG_FLAGS}) 369 | set(ASAN_FLAGS ${GCC_GLANG_ASAN_FLAGS}) 370 | set(UBSAN_FLAGS ${GCC_GLANG_UBSAN_FLAGS}) 371 | set(TSAN_FLAGS ${GCC_GLANG_TSAN_FLAGS}) 372 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 373 | message(STATUS "C++ compiler is Apple Clang") 374 | set(DEGUG_FLAGS ${CLANG_DEBUG_FLAGS}) 375 | set(ASAN_FLAGS ${GCC_GLANG_ASAN_FLAGS}) 376 | set(UBSAN_FLAGS ${GCC_GLANG_UBSAN_FLAGS}) 377 | set(TSAN_FLAGS ${GCC_GLANG_TSAN_FLAGS}) 378 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 379 | message(STATUS "C++ compiler is GNU Compiler Collection") 380 | set(DEGUG_FLAGS ${GCC_DEBUG_FLAGS}) 381 | set(ASAN_FLAGS ${GCC_GLANG_ASAN_FLAGS}) 382 | set(UBSAN_FLAGS ${GCC_GLANG_UBSAN_FLAGS}) 383 | set(TSAN_FLAGS ${GCC_GLANG_TSAN_FLAGS}) 384 | else() 385 | message(STATUS "Unknown compiler ID: ${CMAKE_CXX_COMPILER_ID}") 386 | endif() 387 | 388 | # Initialize sanitizers build type flags from debug 389 | foreach(build_type ASAN UBSAN TSAN SANITIZE) 390 | #set(CMAKE_C_FLAGS_${build_type} "${CMAKE_C_FLAGS_DEBUG}") 391 | set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_DEBUG}") 392 | set(CMAKE_EXE_LINKER_FLAGS_${build_type} "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") 393 | set(CMAKE_SHARED_LINKER_FLAGS_${build_type} "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") 394 | endforeach() 395 | 396 | # Set sanitizers flags 397 | include(CheckLinkerFlag) 398 | message(CHECK_START "Adding Asan flags reported as supported by the C++ compiler") 399 | list(APPEND CMAKE_MESSAGE_INDENT " ") 400 | foreach(flag ${ASAN_FLAGS}) 401 | string(REGEX REPLACE "[-+*/=_]" "_" flag_supported "${flag}") 402 | check_linker_flag(CXX "${flag}" ${flag_supported}) 403 | if(${flag_supported}) 404 | foreach(build_type ASAN SANITIZE) 405 | #set(CMAKE_C_FLAGS_${build_type} "${CMAKE_C_FLAGS_${build_type}} ${flag}") 406 | set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_${build_type}} ${flag}") 407 | set(CMAKE_EXE_LINKER_FLAGS_${build_type} "${CMAKE_EXE_LINKER_FLAGS_${build_type}} ${flag}") 408 | set(CMAKE_SHARED_LINKER_FLAGS_${build_type} "${CMAKE_SHARED_LINKER_FLAGS_${build_type}} ${flag}") 409 | endforeach() 410 | message(STATUS "[O] ${flag}") 411 | else() 412 | message(STATUS "[X] ${flag}") 413 | endif() 414 | endforeach() 415 | list(POP_BACK CMAKE_MESSAGE_INDENT) 416 | message(CHECK_PASS "done") 417 | 418 | message(CHECK_START "Adding UBsan flags reported as supported by the C++ compiler") 419 | list(APPEND CMAKE_MESSAGE_INDENT " ") 420 | foreach(flag ${UBSAN_FLAGS}) 421 | string(REGEX REPLACE "[-+*/=_]" "_" flag_supported "${flag}") 422 | check_linker_flag(CXX "${flag}" ${flag_supported}) 423 | if(${flag_supported}) 424 | foreach(build_type UBSAN SANITIZE) 425 | #set(CMAKE_C_FLAGS_${build_type} "${CMAKE_C_FLAGS_${build_type}} ${flag}") 426 | set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_${build_type}} ${flag}") 427 | set(CMAKE_EXE_LINKER_FLAGS_${build_type} "${CMAKE_EXE_LINKER_FLAGS_${build_type}} ${flag}") 428 | set(CMAKE_SHARED_LINKER_FLAGS_${build_type} "${CMAKE_SHARED_LINKER_FLAGS_${build_type}} ${flag}") 429 | endforeach() 430 | message(STATUS "[O] ${flag}") 431 | else() 432 | message(STATUS "[X] ${flag}") 433 | endif() 434 | endforeach() 435 | list(POP_BACK CMAKE_MESSAGE_INDENT) 436 | message(CHECK_PASS "done") 437 | 438 | message(CHECK_START "Adding Tsan flags reported as supported by the C++ compiler") 439 | list(APPEND CMAKE_MESSAGE_INDENT " ") 440 | foreach(flag ${TSAN_FLAGS}) 441 | string(REGEX REPLACE "[-+*/=_]" "_" flag_supported "${flag}") 442 | check_linker_flag(CXX "${flag}" ${flag_supported}) 443 | if(${flag_supported}) 444 | #set(CMAKE_C_FLAGS_TSAN "${CMAKE_C_FLAGS_TSAN} ${flag}") 445 | set(CMAKE_CXX_FLAGS_TSAN "${CMAKE_CXX_FLAGS_TSAN} ${flag}") 446 | set(CMAKE_EXE_LINKER_FLAGS_TSAN "${CMAKE_EXE_LINKER_FLAGS_TSAN} ${flag}") 447 | set(CMAKE_SHARED_LINKER_FLAGS_TSAN "${CMAKE_SHARED_LINKER_FLAGS_TSAN} ${flag}") 448 | message(STATUS "[O] ${flag}") 449 | else() 450 | message(STATUS "[X] ${flag}") 451 | endif() 452 | endforeach() 453 | list(POP_BACK CMAKE_MESSAGE_INDENT) 454 | message(CHECK_PASS "done") 455 | 456 | # Put sanitizers build type base flags in cache, thus used by projects added by add_subdirectory(...) 457 | foreach(build_type ASAN UBSAN TSAN SANITIZE) 458 | #set(CMAKE_C_FLAGS_${build_type} 459 | # "${CMAKE_C_FLAGS_${build_type}}" 460 | # CACHE STRING "Flags used by the C compiler during ${build_type} builds." 461 | # FORCE 462 | #) 463 | set(CMAKE_CXX_FLAGS_${build_type} 464 | "${CMAKE_CXX_FLAGS_${build_type}}" 465 | CACHE STRING "Flags used by the CXX compiler during ${build_type} builds." 466 | FORCE 467 | ) 468 | set(CMAKE_EXE_LINKER_FLAGS_${build_type} 469 | "${CMAKE_EXE_LINKER_FLAGS_${build_type}}" 470 | CACHE STRING "Flags used by the linker during ${build_type} builds." 471 | FORCE 472 | ) 473 | set(CMAKE_SHARED_LINKER_FLAGS_${build_type} 474 | "${CMAKE_SHARED_LINKER_FLAGS_${build_type}}" 475 | CACHE STRING "Flags used by the linker during the creation of shared libraries during ${build_type} builds." 476 | FORCE 477 | ) 478 | mark_as_advanced( 479 | #CMAKE_C_FLAGS_${build_type} 480 | CMAKE_CXX_FLAGS_${build_type} 481 | CMAKE_EXE_LINKER_FLAGS_${build_type} 482 | CMAKE_SHARED_LINKER_FLAGS_${build_type} 483 | ) 484 | endforeach() 485 | 486 | # Set debug flags 487 | include(CheckCXXCompilerFlag) 488 | message(CHECK_START "Adding debug flags reported as supported by the C++ compiler") 489 | list(APPEND CMAKE_MESSAGE_INDENT " ") 490 | foreach(flag ${DEGUG_FLAGS}) 491 | string(REGEX REPLACE "[-+*/=_]" "_" flag_supported "${flag}") 492 | check_cxx_compiler_flag("${flag}" ${flag_supported}) 493 | if(${flag_supported}) 494 | foreach(build_type DEBUG RELWITHDEBINFO ASAN UBSAN TSAN SANITIZE) 495 | set(CMAKE_CXX_FLAGS_${build_type} "${CMAKE_CXX_FLAGS_${build_type}} ${flag}") 496 | endforeach() 497 | message(STATUS "[O] ${flag}") 498 | else() 499 | message(STATUS "[X] ${flag}") 500 | endif() 501 | endforeach() 502 | list(POP_BACK CMAKE_MESSAGE_INDENT) 503 | message(CHECK_PASS "done") 504 | 505 | list(POP_BACK CMAKE_MESSAGE_INDENT) 506 | message(CHECK_PASS "done") 507 | -------------------------------------------------------------------------------- /tests/src/tests.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Maxime Pinard 3 | // 4 | // Distributed under the MIT license 5 | // See accompanying file LICENSE or copy at 6 | // https://opensource.org/licenses/MIT 7 | // 8 | #include "MultiTakeGenerator.hpp" 9 | #include "RandomBitsetStringGenerator.hpp" 10 | #include "RandomChunkGenerator.hpp" 11 | #include "RandomDynamicBitsetGenerator.hpp" 12 | #include "config.hpp" 13 | #include "utils.hpp" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | TEMPLATE_TEST_CASE("constructors", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 30 | { 31 | SECTION("default constructor") 32 | { 33 | sul::dynamic_bitset bitset; 34 | 35 | REQUIRE(bitset.empty()); 36 | REQUIRE(bitset.size() == 0); 37 | REQUIRE(bitset.capacity() == 0); 38 | REQUIRE(check_consistency(bitset)); 39 | } 40 | 41 | SECTION("nbits and init_val constructor") 42 | { 43 | const std::tuple values = 44 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 45 | random(std::numeric_limits::min(), 46 | std::numeric_limits::max()), 47 | random(1, bits_number))); 48 | const unsigned long long value = std::get<0>(values); 49 | const size_t bits_to_take = std::get<1>(values); 50 | CAPTURE(value, bits_to_take); 51 | 52 | sul::dynamic_bitset bitset(bits_to_take, value); 53 | CAPTURE(bitset); 54 | 55 | // check init value bits 56 | for(size_t i = 0; i < bits_to_take; ++i) 57 | { 58 | CAPTURE(i); 59 | REQUIRE(bitset[i] == bit_value(value, i)); 60 | } 61 | REQUIRE(check_consistency(bitset)); 62 | } 63 | 64 | SECTION("initializer_list constructor") 65 | { 66 | SECTION("one value") 67 | { 68 | const TestType init_value = GENERATE( 69 | take(RANDOM_VECTORS_TO_TEST, 70 | random(std::numeric_limits::min(), std::numeric_limits::max()))); 71 | const sul::dynamic_bitset bitset = {init_value}; 72 | CAPTURE(init_value, bitset); 73 | 74 | // check bits 75 | for(size_t i = 0; i < bits_number; ++i) 76 | { 77 | CAPTURE(i); 78 | REQUIRE(bitset[i] == bit_value(init_value, i)); 79 | } 80 | REQUIRE(check_consistency(bitset)); 81 | } 82 | 83 | SECTION("two values") 84 | { 85 | const std::tuple init_values = 86 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 87 | random(std::numeric_limits::min(), 88 | std::numeric_limits::max()), 89 | random(std::numeric_limits::min(), 90 | std::numeric_limits::max()))); 91 | std::initializer_list init_values_list = {std::get<0>(init_values), std::get<1>(init_values)}; 92 | const sul::dynamic_bitset bitset = init_values_list; 93 | CAPTURE(bitset, init_values_list); 94 | 95 | // check bits 96 | size_t value_i = 0; 97 | for(const TestType& value: init_values_list) 98 | { 99 | for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) 100 | { 101 | CAPTURE(value_i, bit_i); 102 | REQUIRE(bitset[value_i * bits_number + bit_i] == bit_value(value, bit_i)); 103 | } 104 | ++value_i; 105 | } 106 | REQUIRE(check_consistency(bitset)); 107 | } 108 | } 109 | 110 | SECTION("string constructor") 111 | { 112 | const std::tuple values = 113 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 114 | random(std::numeric_limits::min(), 115 | std::numeric_limits::max()), 116 | random(1, bits_number))); 117 | const unsigned long long value = std::get<0>(values); 118 | const size_t bits_to_take = std::get<1>(values); 119 | CAPTURE(value, bits_to_take); 120 | 121 | std::string str(bits_to_take, '0'); 122 | const size_t size = str.size(); 123 | for(size_t i = 0; i < bits_to_take; ++i) 124 | { 125 | if(bit_value(value, i)) 126 | { 127 | str[size - 1 - i] = '1'; 128 | } 129 | } 130 | CAPTURE(str); 131 | 132 | SECTION("full string") 133 | { 134 | SECTION("std::string_view") 135 | { 136 | const sul::dynamic_bitset bitset(std::string_view{str}); 137 | CAPTURE(bitset); 138 | 139 | for(size_t i = 0; i < bits_to_take; ++i) 140 | { 141 | CAPTURE(i); 142 | REQUIRE(bitset[i] == bit_value(value, i)); 143 | } 144 | 145 | REQUIRE(bitset.to_string() == str); 146 | REQUIRE(check_consistency(bitset)); 147 | } 148 | 149 | SECTION("std::string") 150 | { 151 | const sul::dynamic_bitset bitset(str); 152 | CAPTURE(bitset); 153 | 154 | for(size_t i = 0; i < bits_to_take; ++i) 155 | { 156 | CAPTURE(i); 157 | REQUIRE(bitset[i] == bit_value(value, i)); 158 | } 159 | 160 | REQUIRE(bitset.to_string() == str); 161 | REQUIRE(check_consistency(bitset)); 162 | } 163 | 164 | SECTION("const char*") 165 | { 166 | const sul::dynamic_bitset bitset(str.c_str()); 167 | CAPTURE(bitset); 168 | 169 | for(size_t i = 0; i < bits_to_take; ++i) 170 | { 171 | CAPTURE(i); 172 | REQUIRE(bitset[i] == bit_value(value, i)); 173 | } 174 | 175 | REQUIRE(bitset.to_string() == str); 176 | REQUIRE(check_consistency(bitset)); 177 | } 178 | } 179 | 180 | SECTION("partial string") 181 | { 182 | const std::tuple parameters = 183 | GENERATE(multitake(RANDOM_VARIATIONS_TO_TEST, 184 | random(std::numeric_limits::min(), 185 | std::numeric_limits::max()), 186 | random(std::numeric_limits::min(), 187 | std::numeric_limits::max()))); 188 | const size_t pos = std::get<0>(parameters) % bits_to_take; 189 | const size_t n = (pos == (bits_to_take - 1)) ? std::get<1>(parameters) % (bits_to_take - pos) : 0; 190 | CAPTURE(pos, n); 191 | 192 | SECTION("std::string_view") 193 | { 194 | const sul::dynamic_bitset bitset(std::string_view{str}, pos, n); 195 | CAPTURE(bitset); 196 | 197 | for(size_t i = 0; i < n; ++i) 198 | { 199 | CAPTURE(i); 200 | REQUIRE(bitset[i] == bit_value(value, pos + i)); 201 | } 202 | REQUIRE(check_consistency(bitset)); 203 | } 204 | 205 | SECTION("std::string") 206 | { 207 | const sul::dynamic_bitset bitset(str, pos, n); 208 | CAPTURE(bitset); 209 | 210 | for(size_t i = 0; i < n; ++i) 211 | { 212 | CAPTURE(i); 213 | REQUIRE(bitset[i] == bit_value(value, pos + i)); 214 | } 215 | REQUIRE(check_consistency(bitset)); 216 | } 217 | 218 | SECTION("const char*") 219 | { 220 | const sul::dynamic_bitset bitset(str.c_str(), pos, n); 221 | CAPTURE(bitset); 222 | 223 | for(size_t i = 0; i < n; ++i) 224 | { 225 | CAPTURE(i); 226 | REQUIRE(bitset[i] == bit_value(value, pos + i)); 227 | } 228 | REQUIRE(check_consistency(bitset)); 229 | } 230 | } 231 | } 232 | } 233 | 234 | TEMPLATE_TEST_CASE("resize", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 235 | { 236 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 237 | CAPTURE(bitset); 238 | 239 | SECTION("resizing to 0") 240 | { 241 | bitset.resize(0); 242 | REQUIRE(bitset.empty()); 243 | REQUIRE(bitset.size() == 0); 244 | REQUIRE(check_consistency(bitset)); 245 | } 246 | 247 | SECTION("resizing to the same size") 248 | { 249 | const size_t size_save = bitset.size(); 250 | bitset.resize(bitset.size()); 251 | REQUIRE(bitset.size() == size_save); 252 | REQUIRE(check_consistency(bitset)); 253 | } 254 | 255 | SECTION("changing size") 256 | { 257 | size_t size_change = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, random(0, 128))); 258 | const bool new_values = GENERATE(true, false); 259 | CAPTURE(size_change, new_values); 260 | 261 | SECTION("incrementing size") 262 | { 263 | const sul::dynamic_bitset bitset_copy = bitset; 264 | const size_t new_size = bitset.size() + size_change; 265 | bitset.resize(new_size, new_values); 266 | REQUIRE(bitset.size() == new_size); 267 | 268 | for(size_t i = 0; i < bitset_copy.size(); ++i) 269 | { 270 | CAPTURE(i); 271 | REQUIRE(bitset[i] == bitset_copy[i]); 272 | } 273 | for(size_t i = bitset_copy.size(); i < bitset.size(); ++i) 274 | { 275 | CAPTURE(i); 276 | REQUIRE(bitset[i] == new_values); 277 | } 278 | REQUIRE(check_consistency(bitset)); 279 | } 280 | 281 | SECTION("decrementing size") 282 | { 283 | const sul::dynamic_bitset bitset_copy = bitset; 284 | const size_t new_size = size_change > bitset.size() ? 0 : size_change; 285 | bitset.resize(new_size, new_values); 286 | REQUIRE(bitset.size() == new_size); 287 | 288 | for(size_t i = 0; i < bitset.size(); ++i) 289 | { 290 | CAPTURE(i); 291 | REQUIRE(bitset[i] == bitset_copy[i]); 292 | } 293 | REQUIRE(check_consistency(bitset)); 294 | } 295 | } 296 | } 297 | 298 | TEMPLATE_TEST_CASE("clear", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 299 | { 300 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 301 | CAPTURE(bitset); 302 | 303 | bitset.clear(); 304 | REQUIRE(bitset.empty()); 305 | REQUIRE(bitset.size() == 0); 306 | REQUIRE(check_consistency(bitset)); 307 | } 308 | 309 | TEMPLATE_TEST_CASE("push_back", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 310 | { 311 | std::tuple, sul::dynamic_bitset> values = 312 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 313 | randomDynamicBitset(), 314 | randomDynamicBitset(1, 2 * bits_number))); 315 | sul::dynamic_bitset& bitset = std::get<0>(values); 316 | sul::dynamic_bitset& to_push = std::get<1>(values); 317 | CAPTURE(bitset, to_push); 318 | 319 | const sul::dynamic_bitset bitset_copy = bitset; 320 | size_t size = bitset.size(); 321 | 322 | // new bits added 323 | for(size_t i = 0; i < to_push.size(); ++i) 324 | { 325 | CAPTURE(i, size); 326 | bitset.push_back(to_push[i]); 327 | REQUIRE(bitset[size] == to_push[i]); 328 | ++size; 329 | REQUIRE(bitset.size() == size); 330 | } 331 | 332 | // initial bits not changed 333 | for(size_t i = 0; i < bitset_copy.size(); ++i) 334 | { 335 | CAPTURE(i); 336 | REQUIRE(bitset[i] == bitset_copy[i]); 337 | } 338 | REQUIRE(check_consistency(bitset)); 339 | } 340 | 341 | TEMPLATE_TEST_CASE("pop_back", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 342 | { 343 | SECTION("empty bitset") 344 | { 345 | sul::dynamic_bitset bitset; 346 | 347 | bitset.pop_back(); 348 | REQUIRE(bitset.empty()); 349 | REQUIRE(check_consistency(bitset)); 350 | } 351 | 352 | SECTION("non-empty bitset") 353 | { 354 | std::tuple, size_t> values = GENERATE(multitake( 355 | RANDOM_VECTORS_TO_TEST, randomDynamicBitset(), random(1, 2 * bits_number))); 356 | sul::dynamic_bitset& bitset = std::get<0>(values); 357 | size_t to_pop = std::min(bitset.size(), std::get<1>(values)); 358 | CAPTURE(bitset, to_pop); 359 | 360 | const sul::dynamic_bitset bitset_copy = bitset; 361 | size_t size = bitset.size(); 362 | 363 | // bits removed 364 | for(size_t i = 0; i < to_pop; ++i) 365 | { 366 | CAPTURE(i, size); 367 | bitset.pop_back(); 368 | --size; 369 | REQUIRE(bitset.size() == size); 370 | } 371 | 372 | // initial bits not changed 373 | for(size_t i = 0; i < bitset.size(); ++i) 374 | { 375 | CAPTURE(i); 376 | REQUIRE(bitset[i] == bitset_copy[i]); 377 | } 378 | REQUIRE(check_consistency(bitset)); 379 | } 380 | } 381 | 382 | TEMPLATE_TEST_CASE("append", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 383 | { 384 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 385 | CAPTURE(bitset); 386 | const sul::dynamic_bitset bitset_copy = bitset; 387 | 388 | SECTION("one value") 389 | { 390 | const TestType value = 391 | GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 392 | random(std::numeric_limits::min(), std::numeric_limits::max()))); 393 | CAPTURE(value); 394 | 395 | bitset.append(value); 396 | REQUIRE(bitset.size() == (bitset_copy.size() + bits_number)); 397 | 398 | // new bits added 399 | for(size_t i = 0; i < bits_number; ++i) 400 | { 401 | CAPTURE(i); 402 | REQUIRE(bitset[bitset_copy.size() + i] == bit_value(value, i)); 403 | } 404 | 405 | // initial bits not changed 406 | for(size_t i = 0; i < bitset_copy.size(); ++i) 407 | { 408 | CAPTURE(i); 409 | REQUIRE(bitset[i] == bitset_copy[i]); 410 | } 411 | REQUIRE(check_consistency(bitset)); 412 | } 413 | 414 | SECTION("empty initializer_list") 415 | { 416 | bitset.append({}); 417 | REQUIRE(bitset.size() == bitset_copy.size()); 418 | REQUIRE(check_consistency(bitset)); 419 | } 420 | 421 | SECTION("two values initializer_list") 422 | { 423 | const std::tuple init_values = 424 | GENERATE(multitake(RANDOM_VARIATIONS_TO_TEST, 425 | random(std::numeric_limits::min(), 426 | std::numeric_limits::max()), 427 | random(std::numeric_limits::min(), 428 | std::numeric_limits::max()))); 429 | std::initializer_list values = {std::get<0>(init_values), std::get<1>(init_values)}; 430 | CAPTURE(values); 431 | 432 | bitset.append(values); 433 | REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); 434 | 435 | // new bits added 436 | size_t value_i = 0; 437 | for(const TestType& value: values) 438 | { 439 | for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) 440 | { 441 | CAPTURE(value_i, bit_i); 442 | REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] 443 | == bit_value(value, bit_i)); 444 | } 445 | ++value_i; 446 | } 447 | 448 | // initial bits not changed 449 | for(size_t i = 0; i < bitset_copy.size(); ++i) 450 | { 451 | CAPTURE(i); 452 | REQUIRE(bitset[i] == bitset_copy[i]); 453 | } 454 | REQUIRE(check_consistency(bitset)); 455 | } 456 | 457 | SECTION("same iterators") 458 | { 459 | const std::vector values; 460 | 461 | bitset.append(std::cbegin(values), std::cend(values)); 462 | REQUIRE(bitset.size() == bitset_copy.size()); 463 | REQUIRE(check_consistency(bitset)); 464 | } 465 | 466 | SECTION("random access iterators") 467 | { 468 | const std::vector values = GENERATE( 469 | take(RANDOM_VARIATIONS_TO_TEST, 470 | randomChunk( 471 | 2, 5, random(std::numeric_limits::min(), std::numeric_limits::max())))); 472 | CAPTURE(values); 473 | 474 | bitset.append(std::cbegin(values), std::cend(values)); 475 | REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); 476 | 477 | // new bits added 478 | size_t value_i = 0; 479 | for(const TestType& value: values) 480 | { 481 | for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) 482 | { 483 | CAPTURE(value_i, bit_i); 484 | REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] 485 | == bit_value(value, bit_i)); 486 | } 487 | ++value_i; 488 | } 489 | 490 | // initial bits not changed 491 | for(size_t i = 0; i < bitset_copy.size(); ++i) 492 | { 493 | CAPTURE(i); 494 | REQUIRE(bitset[i] == bitset_copy[i]); 495 | } 496 | REQUIRE(check_consistency(bitset)); 497 | } 498 | 499 | SECTION("bidirectional iterators") 500 | { 501 | const std::vector values = GENERATE( 502 | take(RANDOM_VARIATIONS_TO_TEST, 503 | randomChunk( 504 | 2, 5, random(std::numeric_limits::min(), std::numeric_limits::max())))); 505 | CAPTURE(values); 506 | 507 | const std::list values_list(std::cbegin(values), std::cend(values)); 508 | bitset.append(std::cbegin(values_list), std::cend(values_list)); 509 | REQUIRE(bitset.size() == (bitset_copy.size() + values.size() * bits_number)); 510 | 511 | // new bits added 512 | size_t value_i = 0; 513 | for(const TestType& value: values) 514 | { 515 | for(size_t bit_i = 0; bit_i < bits_number; ++bit_i) 516 | { 517 | CAPTURE(value_i, bit_i); 518 | REQUIRE(bitset[bitset_copy.size() + value_i * bits_number + bit_i] 519 | == bit_value(value, bit_i)); 520 | } 521 | ++value_i; 522 | } 523 | 524 | // initial bits not changed 525 | for(size_t i = 0; i < bitset_copy.size(); ++i) 526 | { 527 | CAPTURE(i); 528 | REQUIRE(bitset[i] == bitset_copy[i]); 529 | } 530 | REQUIRE(check_consistency(bitset)); 531 | } 532 | } 533 | 534 | TEMPLATE_TEST_CASE("bitwise operators", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 535 | { 536 | const std::tuple values = 537 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 538 | random(std::numeric_limits::min(), 539 | std::numeric_limits::max()), 540 | random(std::numeric_limits::min(), 541 | std::numeric_limits::max()), 542 | random(1, bits_number))); 543 | unsigned long long value1 = std::get<0>(values); 544 | const unsigned long long value2 = std::get<1>(values); 545 | const size_t bits_to_take = std::get<2>(values); 546 | CAPTURE(value1, value2, bits_to_take); 547 | 548 | sul::dynamic_bitset bitset1(bits_to_take, value1); 549 | const sul::dynamic_bitset bitset2(bits_to_take, value2); 550 | CAPTURE(bitset1, bitset2); 551 | 552 | SECTION("assignement operators") 553 | { 554 | SECTION("operator&=") 555 | { 556 | bitset1 &= bitset2; 557 | value1 &= value2; 558 | 559 | // check bits 560 | for(size_t i = 0; i < bits_to_take; ++i) 561 | { 562 | CAPTURE(i); 563 | REQUIRE(bitset1[i] == bit_value(value1, i)); 564 | } 565 | REQUIRE(check_consistency(bitset1)); 566 | REQUIRE(check_consistency(bitset2)); 567 | } 568 | 569 | SECTION("operator|=") 570 | { 571 | bitset1 |= bitset2; 572 | value1 |= value2; 573 | 574 | // check bits 575 | for(size_t i = 0; i < bits_to_take; ++i) 576 | { 577 | CAPTURE(i); 578 | REQUIRE(bitset1[i] == bit_value(value1, i)); 579 | } 580 | REQUIRE(check_consistency(bitset1)); 581 | REQUIRE(check_consistency(bitset2)); 582 | } 583 | 584 | SECTION("operator^=") 585 | { 586 | bitset1 ^= bitset2; 587 | value1 ^= value2; 588 | 589 | // check bits 590 | for(size_t i = 0; i < bits_to_take; ++i) 591 | { 592 | CAPTURE(i); 593 | REQUIRE(bitset1[i] == bit_value(value1, i)); 594 | } 595 | REQUIRE(check_consistency(bitset1)); 596 | REQUIRE(check_consistency(bitset2)); 597 | } 598 | 599 | SECTION("operator-=") 600 | { 601 | bitset1 -= bitset2; 602 | value1 &= ~value2; 603 | 604 | // check bits 605 | for(size_t i = 0; i < bits_to_take; ++i) 606 | { 607 | CAPTURE(i); 608 | REQUIRE(bitset1[i] == bit_value(value1, i)); 609 | } 610 | REQUIRE(check_consistency(bitset1)); 611 | REQUIRE(check_consistency(bitset2)); 612 | } 613 | } 614 | 615 | SECTION("binary operators") 616 | { 617 | SECTION("operator&") 618 | { 619 | const sul::dynamic_bitset bitset = bitset1 & bitset2; 620 | const unsigned long long value = value1 & value2; 621 | 622 | // check bits 623 | for(size_t i = 0; i < bits_to_take; ++i) 624 | { 625 | CAPTURE(i); 626 | REQUIRE(bitset[i] == bit_value(value, i)); 627 | } 628 | REQUIRE(check_consistency(bitset)); 629 | } 630 | 631 | SECTION("operator|") 632 | { 633 | const sul::dynamic_bitset bitset = bitset1 | bitset2; 634 | const unsigned long long value = value1 | value2; 635 | 636 | // check bits 637 | for(size_t i = 0; i < bits_to_take; ++i) 638 | { 639 | CAPTURE(i); 640 | REQUIRE(bitset[i] == bit_value(value, i)); 641 | } 642 | REQUIRE(check_consistency(bitset)); 643 | } 644 | 645 | SECTION("operator^") 646 | { 647 | const sul::dynamic_bitset bitset = bitset1 ^ bitset2; 648 | const unsigned long long value = value1 ^ value2; 649 | 650 | // check bits 651 | for(size_t i = 0; i < bits_to_take; ++i) 652 | { 653 | CAPTURE(i); 654 | REQUIRE(bitset[i] == bit_value(value, i)); 655 | } 656 | REQUIRE(check_consistency(bitset)); 657 | } 658 | 659 | SECTION("operator-") 660 | { 661 | const sul::dynamic_bitset bitset = bitset1 - bitset2; 662 | const unsigned long long value = value1 & ~value2; 663 | 664 | // check bits 665 | for(size_t i = 0; i < bits_to_take; ++i) 666 | { 667 | CAPTURE(i); 668 | REQUIRE(bitset[i] == bit_value(value, i)); 669 | } 670 | REQUIRE(check_consistency(bitset)); 671 | } 672 | } 673 | } 674 | 675 | TEMPLATE_TEST_CASE("shift operators", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 676 | { 677 | SECTION("null shifts") 678 | { 679 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 680 | CAPTURE(bitset); 681 | 682 | sul::dynamic_bitset bitset_copy = bitset; 683 | 684 | SECTION("assignement operators") 685 | { 686 | bitset <<= 0; 687 | REQUIRE(bitset == bitset_copy); 688 | bitset >>= 0; 689 | REQUIRE(bitset == bitset_copy); 690 | REQUIRE(check_consistency(bitset)); 691 | } 692 | 693 | SECTION("binary operators") 694 | { 695 | sul::dynamic_bitset result = bitset << 0; 696 | REQUIRE(bitset == bitset_copy); 697 | result = bitset >> 0; 698 | REQUIRE(bitset == bitset_copy); 699 | REQUIRE(check_consistency(bitset)); 700 | } 701 | } 702 | 703 | SECTION("real shifts") 704 | { 705 | const std::tuple values = 706 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 707 | random(std::numeric_limits::min(), 708 | std::numeric_limits::max()), 709 | random(1, bits_number), 710 | random(0, bits_number - 1))); 711 | unsigned long long value = std::get<0>(values); 712 | const size_t bits_to_take = std::get<1>(values); 713 | const size_t shift = std::get<2>(values); 714 | CAPTURE(value, bits_to_take, shift); 715 | 716 | sul::dynamic_bitset bitset(bits_to_take, value); 717 | CAPTURE(bitset); 718 | 719 | SECTION("assignement operators") 720 | { 721 | SECTION("operator<<=") 722 | { 723 | bitset <<= shift; 724 | value <<= shift; 725 | 726 | // check bits 727 | for(size_t i = 0; i < bits_to_take; ++i) 728 | { 729 | CAPTURE(i); 730 | REQUIRE(bitset[i] == bit_value(value, i)); 731 | } 732 | REQUIRE(check_consistency(bitset)); 733 | } 734 | 735 | SECTION("operator>>=") 736 | { 737 | bitset >>= shift; 738 | value &= ~static_cast(0) 739 | >> (bits_number - bits_to_take); // set not taken left bits to 0 740 | value >>= shift; 741 | 742 | // check bits 743 | for(size_t i = 0; i < bits_to_take; ++i) 744 | { 745 | CAPTURE(i); 746 | REQUIRE(bitset[i] == bit_value(value, i)); 747 | } 748 | REQUIRE(check_consistency(bitset)); 749 | } 750 | } 751 | 752 | SECTION("binary operators") 753 | { 754 | SECTION("operator<<") 755 | { 756 | const sul::dynamic_bitset shifted_bitset = bitset << shift; 757 | const unsigned long long shifted_value = value << shift; 758 | 759 | // check bits 760 | for(size_t i = 0; i < bits_to_take; ++i) 761 | { 762 | CAPTURE(i); 763 | REQUIRE(shifted_bitset[i] == bit_value(shifted_value, i)); 764 | } 765 | REQUIRE(check_consistency(bitset)); 766 | } 767 | 768 | SECTION("operator>>") 769 | { 770 | const sul::dynamic_bitset shifted_bitset = bitset >> shift; 771 | const unsigned long long shifted_value = 772 | (value & (~static_cast(0) >> (bits_number - bits_to_take))) 773 | >> shift; 774 | 775 | // check bits 776 | for(size_t i = 0; i < bits_to_take; ++i) 777 | { 778 | CAPTURE(i); 779 | REQUIRE(shifted_bitset[i] == bit_value(shifted_value, i)); 780 | } 781 | REQUIRE(check_consistency(bitset)); 782 | } 783 | } 784 | } 785 | } 786 | 787 | TEMPLATE_TEST_CASE("operator~", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 788 | { 789 | const std::tuple values = 790 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 791 | random(std::numeric_limits::min(), 792 | std::numeric_limits::max()), 793 | random(1, bits_number))); 794 | unsigned long long value = std::get<0>(values); 795 | const size_t bits_to_take = std::get<1>(values); 796 | CAPTURE(value, bits_to_take); 797 | 798 | sul::dynamic_bitset bitset(bits_to_take, value); 799 | CAPTURE(bitset); 800 | 801 | // operator~ 802 | bitset = ~bitset; 803 | value = ~value; 804 | 805 | // check bits 806 | for(size_t i = 0; i < bits_to_take; ++i) 807 | { 808 | CAPTURE(i); 809 | REQUIRE(bitset[i] == bit_value(value, i)); 810 | } 811 | REQUIRE(check_consistency(bitset)); 812 | } 813 | 814 | TEMPLATE_TEST_CASE("set reset flip", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 815 | { 816 | sul::dynamic_bitset bitset = GENERATE(take( 817 | RANDOM_VECTORS_TO_TEST, randomDynamicBitset(3 * bits_number, 8 * bits_number))); 818 | CAPTURE(bitset); 819 | 820 | SECTION("range") 821 | { 822 | const std::tuple values = 823 | GENERATE(multitake(RANDOM_VARIATIONS_TO_TEST, 824 | random(std::numeric_limits::min(), 825 | std::numeric_limits::max()), 826 | random(std::numeric_limits::min(), 827 | std::numeric_limits::max()))); 828 | const size_t pos = std::get<0>(values) % bitset.size(); 829 | const size_t len = std::get<1>(values) % (bitset.size() - pos); 830 | CAPTURE(pos, len); 831 | 832 | const sul::dynamic_bitset bitset_copy = bitset; 833 | 834 | SECTION("set") 835 | { 836 | const bool set_to = GENERATE(true, false); 837 | CAPTURE(set_to); 838 | 839 | bitset.set(0, 0, set_to); 840 | REQUIRE(bitset == bitset_copy); 841 | 842 | bitset.set(pos, 0, set_to); 843 | REQUIRE(bitset == bitset_copy); 844 | 845 | bitset.set(pos, len, set_to); 846 | 847 | // check bits 848 | for(size_t i = 0; i < pos; ++i) 849 | { 850 | CAPTURE(i); 851 | REQUIRE(bitset[i] == bitset_copy[i]); 852 | } 853 | for(size_t i = 0; i < len; ++i) 854 | { 855 | CAPTURE(i); 856 | REQUIRE(bitset[pos + i] == set_to); 857 | } 858 | for(size_t i = pos + len; i < bitset.size(); ++i) 859 | { 860 | CAPTURE(i); 861 | REQUIRE(bitset[i] == bitset_copy[i]); 862 | } 863 | REQUIRE(check_consistency(bitset)); 864 | } 865 | 866 | SECTION("reset") 867 | { 868 | bitset.reset(0, 0); 869 | REQUIRE(bitset == bitset_copy); 870 | 871 | bitset.reset(pos, 0); 872 | REQUIRE(bitset == bitset_copy); 873 | 874 | bitset.reset(pos, len); 875 | 876 | // check bits 877 | for(size_t i = 0; i < pos; ++i) 878 | { 879 | CAPTURE(i); 880 | REQUIRE(bitset[i] == bitset_copy[i]); 881 | } 882 | for(size_t i = 0; i < len; ++i) 883 | { 884 | CAPTURE(i); 885 | REQUIRE(bitset[pos + i] == false); 886 | } 887 | for(size_t i = pos + len; i < bitset.size(); ++i) 888 | { 889 | CAPTURE(i); 890 | REQUIRE(bitset[i] == bitset_copy[i]); 891 | } 892 | REQUIRE(check_consistency(bitset)); 893 | } 894 | 895 | SECTION("flip") 896 | { 897 | bitset.flip(0, 0); 898 | REQUIRE(bitset == bitset_copy); 899 | 900 | bitset.flip(pos, 0); 901 | REQUIRE(bitset == bitset_copy); 902 | 903 | bitset.flip(pos, len); 904 | 905 | // check bits 906 | for(size_t i = 0; i < pos; ++i) 907 | { 908 | CAPTURE(i); 909 | REQUIRE(bitset[i] == bitset_copy[i]); 910 | } 911 | for(size_t i = 0; i < len; ++i) 912 | { 913 | CAPTURE(i); 914 | REQUIRE(bitset[pos + i] != bitset_copy[pos + i]); 915 | } 916 | for(size_t i = pos + len; i < bitset.size(); ++i) 917 | { 918 | CAPTURE(i); 919 | REQUIRE(bitset[i] == bitset_copy[i]); 920 | } 921 | REQUIRE(check_consistency(bitset)); 922 | } 923 | } 924 | 925 | SECTION("single bit") 926 | { 927 | const size_t pos = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 928 | random(std::numeric_limits::min(), 929 | std::numeric_limits::max()))) 930 | % bitset.size(); 931 | CAPTURE(pos); 932 | 933 | const sul::dynamic_bitset bitset_copy = bitset; 934 | 935 | SECTION("set") 936 | { 937 | const bool set_to = GENERATE(true, false); 938 | CAPTURE(set_to); 939 | bitset.set(pos, set_to); 940 | 941 | // check bits 942 | for(size_t i = 0; i < pos; ++i) 943 | { 944 | CAPTURE(i); 945 | REQUIRE(bitset[i] == bitset_copy[i]); 946 | } 947 | REQUIRE(bitset[pos] == set_to); 948 | for(size_t i = pos + 1; i < bitset.size(); ++i) 949 | { 950 | CAPTURE(i); 951 | REQUIRE(bitset[i] == bitset_copy[i]); 952 | } 953 | REQUIRE(check_consistency(bitset)); 954 | } 955 | 956 | SECTION("reset") 957 | { 958 | bitset.reset(pos); 959 | 960 | // check bits 961 | for(size_t i = 0; i < pos; ++i) 962 | { 963 | CAPTURE(i); 964 | REQUIRE(bitset[i] == bitset_copy[i]); 965 | } 966 | REQUIRE(bitset[pos] == false); 967 | for(size_t i = pos + 1; i < bitset.size(); ++i) 968 | { 969 | CAPTURE(i); 970 | REQUIRE(bitset[i] == bitset_copy[i]); 971 | } 972 | REQUIRE(check_consistency(bitset)); 973 | } 974 | 975 | SECTION("flip") 976 | { 977 | bitset.flip(pos); 978 | 979 | // check bits 980 | for(size_t i = 0; i < pos; ++i) 981 | { 982 | CAPTURE(i); 983 | REQUIRE(bitset[i] == bitset_copy[i]); 984 | } 985 | REQUIRE(bitset[pos] != bitset_copy[pos]); 986 | for(size_t i = pos + 1; i < bitset.size(); ++i) 987 | { 988 | CAPTURE(i); 989 | REQUIRE(bitset[i] == bitset_copy[i]); 990 | } 991 | REQUIRE(check_consistency(bitset)); 992 | } 993 | } 994 | 995 | SECTION("all bits") 996 | { 997 | SECTION("set") 998 | { 999 | bitset.set(); 1000 | 1001 | // check bits 1002 | REQUIRE(bitset.all()); 1003 | REQUIRE(check_consistency(bitset)); 1004 | } 1005 | 1006 | SECTION("reset") 1007 | { 1008 | bitset.reset(); 1009 | 1010 | // check bits 1011 | REQUIRE(bitset.none()); 1012 | REQUIRE(check_consistency(bitset)); 1013 | } 1014 | 1015 | SECTION("flip") 1016 | { 1017 | const sul::dynamic_bitset bitset_copy = bitset; 1018 | bitset.flip(); 1019 | 1020 | // check bits 1021 | for(size_t i = 0; i < bitset.size(); ++i) 1022 | { 1023 | CAPTURE(i); 1024 | REQUIRE(bitset[i] != bitset_copy[i]); 1025 | } 1026 | REQUIRE(check_consistency(bitset)); 1027 | } 1028 | } 1029 | } 1030 | 1031 | TEMPLATE_TEST_CASE("test", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1032 | { 1033 | const std::tuple values = 1034 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1035 | random(std::numeric_limits::min(), 1036 | std::numeric_limits::max()), 1037 | random(1, bits_number))); 1038 | unsigned long long value = std::get<0>(values); 1039 | const size_t bits_to_take = std::get<1>(values); 1040 | CAPTURE(value, bits_to_take); 1041 | 1042 | sul::dynamic_bitset bitset(bits_to_take, value); 1043 | CAPTURE(bitset); 1044 | 1045 | // check 1046 | for(size_t i = 0; i < bits_to_take; ++i) 1047 | { 1048 | CAPTURE(i); 1049 | REQUIRE(bitset.test(i) == bit_value(value, i)); 1050 | } 1051 | } 1052 | 1053 | TEMPLATE_TEST_CASE("test_set", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1054 | { 1055 | const std::tuple values = 1056 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1057 | random(std::numeric_limits::min(), 1058 | std::numeric_limits::max()), 1059 | random(1, bits_number))); 1060 | unsigned long long value = std::get<0>(values); 1061 | const size_t bits_to_take = std::get<1>(values); 1062 | const bool set_to = GENERATE(true, false); 1063 | CAPTURE(value, bits_to_take, set_to); 1064 | 1065 | sul::dynamic_bitset bitset(bits_to_take, value); 1066 | CAPTURE(bitset); 1067 | 1068 | // check 1069 | for(size_t i = 0; i < bits_to_take; ++i) 1070 | { 1071 | CAPTURE(i); 1072 | REQUIRE(bitset.test_set(i, set_to) == bit_value(value, i)); 1073 | REQUIRE(bitset[i] == set_to); 1074 | } 1075 | REQUIRE(check_consistency(bitset)); 1076 | } 1077 | 1078 | TEMPLATE_TEST_CASE("all any none", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1079 | { 1080 | SECTION("empty bitset") 1081 | { 1082 | sul::dynamic_bitset bitset; 1083 | CAPTURE(bitset); 1084 | 1085 | REQUIRE(bitset.all()); 1086 | REQUIRE_FALSE(bitset.any()); 1087 | REQUIRE(bitset.none()); 1088 | } 1089 | 1090 | SECTION("non-empty bitset") 1091 | { 1092 | const size_t bitset_size = 1093 | GENERATE(take(RANDOM_VECTORS_TO_TEST, random(3 * bits_number, 8 * bits_number))); 1094 | CAPTURE(bitset_size); 1095 | 1096 | sul::dynamic_bitset bitset(bitset_size); 1097 | CAPTURE(bitset); 1098 | 1099 | SECTION("all bits on") 1100 | { 1101 | bitset.set(); 1102 | REQUIRE(bitset.all()); 1103 | REQUIRE(bitset.any()); 1104 | REQUIRE_FALSE(bitset.none()); 1105 | } 1106 | 1107 | SECTION("one bit on") 1108 | { 1109 | const size_t pos = 1110 | GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 1111 | random(std::numeric_limits::min(), 1112 | std::numeric_limits::max()))) 1113 | % bitset_size; 1114 | CAPTURE(pos); 1115 | bitset.reset(); 1116 | bitset.set(pos); 1117 | REQUIRE_FALSE(bitset.all()); 1118 | REQUIRE(bitset.any()); 1119 | REQUIRE_FALSE(bitset.none()); 1120 | } 1121 | 1122 | SECTION("no bit on") 1123 | { 1124 | bitset.reset(); 1125 | REQUIRE_FALSE(bitset.all()); 1126 | REQUIRE_FALSE(bitset.any()); 1127 | REQUIRE(bitset.none()); 1128 | } 1129 | } 1130 | } 1131 | 1132 | TEMPLATE_TEST_CASE("array subscript operator", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1133 | { 1134 | const std::tuple values = 1135 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1136 | random(std::numeric_limits::min(), 1137 | std::numeric_limits::max()), 1138 | random(1, bits_number))); 1139 | unsigned long long value = std::get<0>(values); 1140 | const size_t bits_to_take = std::get<1>(values); 1141 | CAPTURE(value, bits_to_take); 1142 | 1143 | sul::dynamic_bitset bitset(bits_to_take, value); 1144 | CAPTURE(bitset); 1145 | 1146 | SECTION("access") 1147 | { 1148 | for(size_t i = 0; i < bits_to_take; ++i) 1149 | { 1150 | CAPTURE(i); 1151 | REQUIRE(bitset[i] == bit_value(value, i)); 1152 | } 1153 | REQUIRE(check_consistency(bitset)); 1154 | } 1155 | 1156 | SECTION("reference operator=") 1157 | { 1158 | const unsigned long long other_value = 1159 | GENERATE(take(1, 1160 | random(std::numeric_limits::min(), 1161 | std::numeric_limits::max()))); 1162 | sul::dynamic_bitset other_bitset(bits_to_take, other_value); 1163 | CAPTURE(other_bitset); 1164 | 1165 | SECTION("with bool") 1166 | { 1167 | for(size_t i = 0; i < bits_to_take; ++i) 1168 | { 1169 | bitset[i] = other_bitset.test(i); 1170 | } 1171 | REQUIRE(bitset == other_bitset); 1172 | REQUIRE(check_consistency(bitset)); 1173 | } 1174 | 1175 | SECTION("with reference") 1176 | { 1177 | for(size_t i = 0; i < bits_to_take; ++i) 1178 | { 1179 | bitset[i] = other_bitset[i]; 1180 | } 1181 | REQUIRE(bitset == other_bitset); 1182 | REQUIRE(check_consistency(bitset)); 1183 | } 1184 | } 1185 | 1186 | SECTION("reference binary operators") 1187 | { 1188 | const unsigned long long other_value = 1189 | GENERATE(take(1, 1190 | random(std::numeric_limits::min(), 1191 | std::numeric_limits::max()))); 1192 | sul::dynamic_bitset other_bitset(bits_to_take, other_value); 1193 | CAPTURE(other_bitset); 1194 | 1195 | sul::dynamic_bitset bitset_copy = bitset; 1196 | 1197 | SECTION("operator&=") 1198 | { 1199 | for(size_t i = 0; i < bits_to_take; ++i) 1200 | { 1201 | bitset[i] &= other_bitset[i]; 1202 | } 1203 | 1204 | bitset_copy &= other_bitset; 1205 | REQUIRE(bitset == bitset_copy); 1206 | REQUIRE(check_consistency(bitset)); 1207 | } 1208 | 1209 | SECTION("operator|=") 1210 | { 1211 | for(size_t i = 0; i < bits_to_take; ++i) 1212 | { 1213 | bitset[i] |= other_bitset[i]; 1214 | } 1215 | 1216 | bitset_copy |= other_bitset; 1217 | REQUIRE(bitset == bitset_copy); 1218 | REQUIRE(check_consistency(bitset)); 1219 | } 1220 | 1221 | SECTION("operator^=") 1222 | { 1223 | for(size_t i = 0; i < bits_to_take; ++i) 1224 | { 1225 | bitset[i] ^= other_bitset[i]; 1226 | } 1227 | 1228 | bitset_copy ^= other_bitset; 1229 | REQUIRE(bitset == bitset_copy); 1230 | REQUIRE(check_consistency(bitset)); 1231 | } 1232 | 1233 | SECTION("operator-=") 1234 | { 1235 | for(size_t i = 0; i < bits_to_take; ++i) 1236 | { 1237 | bitset[i] -= other_bitset[i]; 1238 | } 1239 | 1240 | bitset_copy -= other_bitset; 1241 | REQUIRE(bitset == bitset_copy); 1242 | REQUIRE(check_consistency(bitset)); 1243 | } 1244 | } 1245 | 1246 | SECTION("reference operator~") 1247 | { 1248 | for(size_t i = 0; i < bits_to_take; ++i) 1249 | { 1250 | CAPTURE(i); 1251 | REQUIRE(~bitset[i] == !bit_value(value, i)); 1252 | } 1253 | REQUIRE(check_consistency(bitset)); 1254 | } 1255 | 1256 | SECTION("set reset flip assign") 1257 | { 1258 | const size_t pos = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 1259 | random(std::numeric_limits::min(), 1260 | std::numeric_limits::max()))) 1261 | % bits_to_take; 1262 | CAPTURE(pos); 1263 | 1264 | SECTION("set") 1265 | { 1266 | bitset[pos].set(); 1267 | REQUIRE(bitset[pos] == true); 1268 | REQUIRE(check_consistency(bitset)); 1269 | } 1270 | 1271 | SECTION("reset") 1272 | { 1273 | bitset[pos].reset(); 1274 | REQUIRE(bitset[pos] == false); 1275 | REQUIRE(check_consistency(bitset)); 1276 | } 1277 | 1278 | SECTION("flip") 1279 | { 1280 | bitset[pos].flip(); 1281 | REQUIRE(bitset[pos] == !bit_value(value, pos)); 1282 | REQUIRE(check_consistency(bitset)); 1283 | } 1284 | 1285 | SECTION("assign") 1286 | { 1287 | const bool new_value = GENERATE(true, false); 1288 | CAPTURE(new_value); 1289 | bitset[pos].assign(new_value); 1290 | REQUIRE(bitset[pos] == new_value); 1291 | REQUIRE(check_consistency(bitset)); 1292 | } 1293 | } 1294 | } 1295 | 1296 | TEMPLATE_TEST_CASE("size num_blocks empty capacity", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1297 | { 1298 | const std::tuple values = 1299 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1300 | random(std::numeric_limits::min(), 1301 | std::numeric_limits::max()), 1302 | random(1, bits_number))); 1303 | unsigned long long value = std::get<0>(values); 1304 | const size_t bits_to_take = std::get<1>(values); 1305 | CAPTURE(value, bits_to_take); 1306 | 1307 | sul::dynamic_bitset bitset(bits_to_take, value); 1308 | CAPTURE(bitset); 1309 | 1310 | // size 1311 | REQUIRE(bitset.size() == bits_to_take); 1312 | 1313 | // num_blocks 1314 | const size_t num_blocks = 1315 | bits_to_take / bits_number + static_cast(bits_to_take % bits_number > 0); 1316 | REQUIRE(bitset.num_blocks() == num_blocks); 1317 | 1318 | const size_t old_capacity = bitset.capacity(); 1319 | bitset.clear(); 1320 | REQUIRE(bitset.empty()); 1321 | 1322 | REQUIRE(bitset.capacity() == old_capacity); 1323 | } 1324 | 1325 | TEMPLATE_TEST_CASE("reserve shrink_to_fit", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1326 | { 1327 | const size_t size = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, random(1, 8 * bits_number))); 1328 | CAPTURE(size); 1329 | 1330 | sul::dynamic_bitset bitset; 1331 | bitset.reserve(size); 1332 | 1333 | REQUIRE(bitset.capacity() > 0); 1334 | 1335 | bitset.shrink_to_fit(); 1336 | REQUIRE(check_consistency(bitset)); 1337 | } 1338 | 1339 | TEMPLATE_TEST_CASE("is_subset_of is_proper_subset_of", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1340 | { 1341 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1342 | CAPTURE(bitset); 1343 | 1344 | const sul::dynamic_bitset bitset_copy = bitset; 1345 | 1346 | SECTION("subset") 1347 | { 1348 | REQUIRE(bitset.is_subset_of(bitset_copy) == true); 1349 | REQUIRE(bitset.is_proper_subset_of(bitset_copy) == false); 1350 | } 1351 | 1352 | SECTION("proper subset") 1353 | { 1354 | if(bitset.any()) 1355 | { 1356 | const size_t bit_to_reset = 1357 | GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 1358 | random(std::numeric_limits::min(), 1359 | std::numeric_limits::max()))) 1360 | % bitset.count(); 1361 | size_t bit_to_reset_pos = bitset.find_first(); 1362 | for(size_t i = 1; i < bit_to_reset; ++i) 1363 | { 1364 | bit_to_reset_pos = bitset.find_next(bit_to_reset_pos); 1365 | } 1366 | bitset.reset(bit_to_reset_pos); 1367 | 1368 | REQUIRE(bitset.is_subset_of(bitset_copy) == true); 1369 | REQUIRE(bitset.is_proper_subset_of(bitset_copy) == true); 1370 | } 1371 | } 1372 | 1373 | SECTION("not a subset") 1374 | { 1375 | if(!bitset.all()) 1376 | { 1377 | const sul::dynamic_bitset not_bitset = ~bitset; 1378 | const size_t bit_to_set = 1379 | GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 1380 | random(std::numeric_limits::min(), 1381 | std::numeric_limits::max()))) 1382 | % not_bitset.count(); 1383 | size_t bit_to_set_pos = not_bitset.find_first(); 1384 | for(size_t i = 1; i < bit_to_set; ++i) 1385 | { 1386 | bit_to_set_pos = not_bitset.find_next(bit_to_set_pos); 1387 | } 1388 | bitset.set(bit_to_set_pos); 1389 | 1390 | REQUIRE(bitset.is_subset_of(bitset_copy) == false); 1391 | REQUIRE(bitset.is_proper_subset_of(bitset_copy) == false); 1392 | } 1393 | } 1394 | } 1395 | 1396 | TEMPLATE_TEST_CASE("intersects", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1397 | { 1398 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1399 | CAPTURE(bitset); 1400 | 1401 | // require non 0-only bitset 1402 | if(bitset.none()) 1403 | { 1404 | bitset.push_back(true); 1405 | } 1406 | 1407 | const sul::dynamic_bitset bitset_copy = bitset; 1408 | 1409 | REQUIRE(bitset.intersects(bitset_copy)); 1410 | 1411 | if(!bitset.all()) 1412 | { 1413 | // flip first bit at 0 1414 | for(size_t i = 0; i < bitset.size(); ++i) 1415 | { 1416 | if(bitset.test(i) == false) 1417 | { 1418 | bitset.flip(i); 1419 | break; 1420 | } 1421 | } 1422 | REQUIRE(bitset.intersects(bitset_copy)); 1423 | } 1424 | 1425 | bitset.flip(); 1426 | REQUIRE_FALSE(bitset.intersects(bitset_copy)); 1427 | bitset.reset(); 1428 | REQUIRE_FALSE(bitset.intersects(bitset_copy)); 1429 | } 1430 | 1431 | TEMPLATE_TEST_CASE("swap", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1432 | { 1433 | const std::tuple, sul::dynamic_bitset> bitsets = 1434 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, randomDynamicBitset(), randomDynamicBitset())); 1435 | sul::dynamic_bitset bitset1 = std::get<0>(bitsets); 1436 | sul::dynamic_bitset bitset2 = std::get<1>(bitsets); 1437 | CAPTURE(bitset1, bitset2); 1438 | 1439 | SECTION("member function") 1440 | { 1441 | const sul::dynamic_bitset bitset1_copy = bitset1; 1442 | const sul::dynamic_bitset bitset2_copy = bitset2; 1443 | bitset1.swap(bitset2); 1444 | REQUIRE(bitset1 == bitset2_copy); 1445 | REQUIRE(bitset2 == bitset1_copy); 1446 | REQUIRE(check_consistency(bitset1)); 1447 | REQUIRE(check_consistency(bitset2)); 1448 | } 1449 | 1450 | SECTION("external function") 1451 | { 1452 | const sul::dynamic_bitset bitset1_copy = bitset1; 1453 | const sul::dynamic_bitset bitset2_copy = bitset2; 1454 | swap(bitset1, bitset2); 1455 | REQUIRE(bitset1 == bitset2_copy); 1456 | REQUIRE(bitset2 == bitset1_copy); 1457 | REQUIRE(check_consistency(bitset1)); 1458 | REQUIRE(check_consistency(bitset2)); 1459 | } 1460 | } 1461 | 1462 | TEMPLATE_TEST_CASE("get_allocator", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1463 | { 1464 | sul::dynamic_bitset bitset; 1465 | static_cast(bitset.get_allocator()); // avoid unused warnings 1466 | } 1467 | 1468 | TEMPLATE_TEST_CASE("to_string", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1469 | { 1470 | const std::tuple values = 1471 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1472 | random(std::numeric_limits::min(), 1473 | std::numeric_limits::max()), 1474 | random(1, bits_number))); 1475 | unsigned long long value = std::get<0>(values); 1476 | const size_t bits_to_take = std::get<1>(values); 1477 | CAPTURE(value, bits_to_take); 1478 | 1479 | sul::dynamic_bitset bitset(bits_to_take, value); 1480 | CAPTURE(bitset); 1481 | 1482 | std::string string; 1483 | string.reserve(bits_to_take); 1484 | for(size_t i = bits_to_take - 1; i > 0; --i) 1485 | { 1486 | string.push_back(bit_value(value, i) ? '1' : '0'); 1487 | } 1488 | string.push_back(bit_value(value, 0) ? '1' : '0'); 1489 | 1490 | REQUIRE(bitset.to_string() == string); 1491 | } 1492 | 1493 | TEMPLATE_TEST_CASE("to_ulong", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1494 | { 1495 | SECTION("empty bitset") 1496 | { 1497 | const sul::dynamic_bitset bitset; 1498 | 1499 | REQUIRE(bitset.to_ulong() == 0); 1500 | } 1501 | 1502 | SECTION("non-empty bitset") 1503 | { 1504 | SECTION("value") 1505 | { 1506 | const std::tuple values = 1507 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1508 | random(std::numeric_limits::min(), 1509 | std::numeric_limits::max()), 1510 | random(1, bits_number))); 1511 | unsigned long long value = std::get<0>(values); 1512 | const size_t bits_to_take = std::get<1>(values); 1513 | CAPTURE(value, bits_to_take); 1514 | 1515 | sul::dynamic_bitset bitset(bits_to_take, value); 1516 | CAPTURE(bitset); 1517 | 1518 | unsigned long long bits_taken_mask = 1519 | one_block >> (bits_number - bits_to_take); 1520 | unsigned long ulong_value = static_cast(value & bits_taken_mask); 1521 | 1522 | REQUIRE(bitset.to_ulong() == ulong_value); 1523 | } 1524 | 1525 | SECTION("overflow exception") 1526 | { 1527 | sul::dynamic_bitset bitset = 1528 | GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1529 | CAPTURE(bitset); 1530 | 1531 | size_t last = sul::dynamic_bitset::npos; 1532 | bitset.iterate_bits_on([&last](size_t bit_pos) noexcept { last = bit_pos; }); 1533 | if(last == sul::dynamic_bitset::npos || last <= bits_number) 1534 | { 1535 | do 1536 | { 1537 | bitset.push_back(true); 1538 | } while(bitset.size() <= bits_number); 1539 | } 1540 | CAPTURE(bitset); 1541 | 1542 | REQUIRE_THROWS(bitset.to_ulong()); 1543 | } 1544 | } 1545 | } 1546 | 1547 | TEMPLATE_TEST_CASE("to_ullong", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1548 | { 1549 | SECTION("empty bitset") 1550 | { 1551 | const sul::dynamic_bitset bitset; 1552 | 1553 | REQUIRE(bitset.to_ullong() == 0); 1554 | } 1555 | 1556 | SECTION("non-empty bitset") 1557 | { 1558 | SECTION("value") 1559 | { 1560 | const std::tuple values = 1561 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1562 | random(std::numeric_limits::min(), 1563 | std::numeric_limits::max()), 1564 | random(1, bits_number))); 1565 | unsigned long long value = std::get<0>(values); 1566 | const size_t bits_to_take = std::get<1>(values); 1567 | CAPTURE(value, bits_to_take); 1568 | 1569 | sul::dynamic_bitset bitset(bits_to_take, value); 1570 | CAPTURE(bitset); 1571 | 1572 | unsigned long long bits_taken_mask = 1573 | one_block >> (bits_number - bits_to_take); 1574 | unsigned long long ullong_value = value & bits_taken_mask; 1575 | 1576 | REQUIRE(bitset.to_ullong() == ullong_value); 1577 | } 1578 | 1579 | SECTION("overflow exception") 1580 | { 1581 | sul::dynamic_bitset bitset = 1582 | GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1583 | CAPTURE(bitset); 1584 | 1585 | size_t last = sul::dynamic_bitset::npos; 1586 | bitset.iterate_bits_on([&last](size_t bit_pos) noexcept { last = bit_pos; }); 1587 | if(last == sul::dynamic_bitset::npos || last <= bits_number) 1588 | { 1589 | do 1590 | { 1591 | bitset.push_back(true); 1592 | } while(bitset.size() <= bits_number); 1593 | } 1594 | CAPTURE(bitset); 1595 | 1596 | REQUIRE_THROWS(bitset.to_ullong()); 1597 | } 1598 | } 1599 | } 1600 | 1601 | TEMPLATE_TEST_CASE("iterate_bits_on", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1602 | { 1603 | const std::tuple values = 1604 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1605 | random(std::numeric_limits::min(), 1606 | std::numeric_limits::max()), 1607 | random(1, bits_number))); 1608 | unsigned long long value = std::get<0>(values); 1609 | const size_t bits_to_take = std::get<1>(values); 1610 | CAPTURE(value, bits_to_take); 1611 | 1612 | sul::dynamic_bitset bitset(bits_to_take, value); 1613 | CAPTURE(bitset); 1614 | 1615 | SECTION("return void") 1616 | { 1617 | SECTION("no parameters") 1618 | { 1619 | size_t current_check_bit = 0; 1620 | bitset.iterate_bits_on( 1621 | [&](size_t bit_pos) 1622 | { 1623 | while(current_check_bit < bit_pos) 1624 | { 1625 | REQUIRE(bitset[current_check_bit] == false); 1626 | ++current_check_bit; 1627 | } 1628 | REQUIRE(bitset[bit_pos] == true); 1629 | ++current_check_bit; 1630 | }); 1631 | for(size_t i = current_check_bit; i < bits_to_take; ++i) 1632 | { 1633 | REQUIRE(bitset[i] == false); 1634 | } 1635 | } 1636 | 1637 | SECTION("parameters") 1638 | { 1639 | sul::dynamic_bitset check_bitset(bits_to_take); 1640 | bitset.iterate_bits_on([](size_t bit_pos, sul::dynamic_bitset& check_bitset_) 1641 | { check_bitset_[bit_pos] = true; }, 1642 | check_bitset); 1643 | REQUIRE(check_bitset == bitset); 1644 | } 1645 | } 1646 | 1647 | SECTION("return bool") 1648 | { 1649 | if(bitset.count() == 0) 1650 | { 1651 | bitset.push_back(true); 1652 | } 1653 | const size_t stop_at_bit = 1654 | GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 1655 | random(std::numeric_limits::min(), 1656 | std::numeric_limits::max()))) 1657 | % bitset.count() 1658 | + 1; 1659 | 1660 | SECTION("no parameters") 1661 | { 1662 | size_t current_check_bit = 0; 1663 | size_t bit_count = 0; 1664 | bitset.iterate_bits_on( 1665 | [&](size_t bit_pos) 1666 | { 1667 | while(current_check_bit < bit_pos) 1668 | { 1669 | REQUIRE(bitset[current_check_bit] == false); 1670 | ++current_check_bit; 1671 | } 1672 | REQUIRE(bitset[bit_pos] == true); 1673 | ++current_check_bit; 1674 | 1675 | ++bit_count; 1676 | return bit_count < stop_at_bit; 1677 | }); 1678 | REQUIRE(bit_count == stop_at_bit); 1679 | } 1680 | 1681 | SECTION("parameters") 1682 | { 1683 | size_t bit_count = 0; 1684 | size_t last_bit_pos = 0; 1685 | sul::dynamic_bitset check_bitset(bitset.size()); 1686 | bitset.iterate_bits_on( 1687 | [](size_t bit_pos, 1688 | sul::dynamic_bitset& check_bitset_, 1689 | size_t& bit_count_, 1690 | size_t& last_bit_pos_, 1691 | const size_t stop_at_bit_) 1692 | { 1693 | check_bitset_[bit_pos] = true; 1694 | last_bit_pos_ = bit_pos; 1695 | 1696 | ++bit_count_; 1697 | return bit_count_ < stop_at_bit_; 1698 | }, 1699 | check_bitset, 1700 | bit_count, 1701 | last_bit_pos, 1702 | stop_at_bit); 1703 | REQUIRE(bit_count == stop_at_bit); 1704 | 1705 | check_bitset.resize(last_bit_pos); 1706 | bitset.resize(last_bit_pos); 1707 | REQUIRE(check_bitset == bitset); 1708 | } 1709 | } 1710 | } 1711 | 1712 | TEMPLATE_TEST_CASE("data", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1713 | { 1714 | SECTION("const") 1715 | { 1716 | const sul::dynamic_bitset bitset = 1717 | GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1718 | CAPTURE(bitset); 1719 | 1720 | if(!bitset.empty()) 1721 | { 1722 | REQUIRE(bitset.data() != nullptr); 1723 | } 1724 | REQUIRE(check_consistency(bitset)); 1725 | } 1726 | 1727 | SECTION("non-const") 1728 | { 1729 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1730 | CAPTURE(bitset); 1731 | 1732 | if(!bitset.empty()) 1733 | { 1734 | REQUIRE(bitset.data() != nullptr); 1735 | } 1736 | REQUIRE(check_consistency(bitset)); 1737 | } 1738 | } 1739 | 1740 | TEMPLATE_TEST_CASE("operator== operator!=", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1741 | { 1742 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1743 | CAPTURE(bitset); 1744 | 1745 | SECTION("same") 1746 | { 1747 | const sul::dynamic_bitset bitset_copy = bitset; 1748 | REQUIRE(bitset == bitset_copy); 1749 | REQUIRE_FALSE(bitset != bitset_copy); 1750 | } 1751 | 1752 | SECTION("different size and same bits") 1753 | { 1754 | const sul::dynamic_bitset bitset_copy = bitset; 1755 | bitset.push_back(true); 1756 | REQUIRE_FALSE(bitset == bitset_copy); 1757 | REQUIRE_FALSE(bitset_copy == bitset); 1758 | REQUIRE(bitset != bitset_copy); 1759 | REQUIRE(bitset_copy != bitset); 1760 | } 1761 | 1762 | SECTION("same size and different bits") 1763 | { 1764 | if(bitset.empty()) 1765 | { 1766 | bitset.push_back(true); 1767 | } 1768 | const sul::dynamic_bitset bitset_copy = bitset; 1769 | 1770 | size_t pos = GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 1771 | random(std::numeric_limits::min(), 1772 | std::numeric_limits::max()))) 1773 | % bitset.size(); 1774 | CAPTURE(pos); 1775 | bitset.flip(pos); 1776 | REQUIRE_FALSE(bitset == bitset_copy); 1777 | REQUIRE_FALSE(bitset_copy == bitset); 1778 | REQUIRE(bitset != bitset_copy); 1779 | REQUIRE(bitset_copy != bitset); 1780 | } 1781 | } 1782 | 1783 | TEMPLATE_TEST_CASE("operator< operator<= operator> operator>=", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1784 | { 1785 | SECTION("2 empty bitsets") 1786 | { 1787 | const sul::dynamic_bitset bitset1; 1788 | const sul::dynamic_bitset bitset2; 1789 | 1790 | REQUIRE_FALSE(bitset1 < bitset2); 1791 | REQUIRE_FALSE(bitset2 < bitset1); 1792 | REQUIRE(bitset1 <= bitset2); 1793 | REQUIRE(bitset2 <= bitset1); 1794 | 1795 | REQUIRE_FALSE(bitset1 > bitset2); 1796 | REQUIRE_FALSE(bitset2 > bitset1); 1797 | REQUIRE(bitset1 >= bitset2); 1798 | REQUIRE(bitset2 >= bitset1); 1799 | } 1800 | 1801 | SECTION("1 empty bitset") 1802 | { 1803 | const sul::dynamic_bitset bitset = 1804 | GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1805 | const sul::dynamic_bitset empty_bitset; 1806 | CAPTURE(bitset); 1807 | 1808 | REQUIRE(empty_bitset < bitset); 1809 | REQUIRE_FALSE(bitset < empty_bitset); 1810 | REQUIRE(empty_bitset <= bitset); 1811 | REQUIRE_FALSE(bitset <= empty_bitset); 1812 | 1813 | REQUIRE_FALSE(empty_bitset > bitset); 1814 | REQUIRE(bitset > empty_bitset); 1815 | REQUIRE_FALSE(empty_bitset >= bitset); 1816 | REQUIRE(bitset >= empty_bitset); 1817 | } 1818 | 1819 | SECTION("non-empty bitsets") 1820 | { 1821 | const std::tuple values = 1822 | GENERATE(multitake(RANDOM_VECTORS_TO_TEST, 1823 | random(std::numeric_limits::min(), 1824 | std::numeric_limits::max()), 1825 | random(std::numeric_limits::min(), 1826 | std::numeric_limits::max()))); 1827 | const unsigned long long value1 = std::get<0>(values); 1828 | const unsigned long long value2 = std::get<1>(values) % value1; // value2 != value1 1829 | const size_t bits_to_take = bits_number; 1830 | CAPTURE(value1, value2, bits_to_take); 1831 | 1832 | SECTION("same") 1833 | { 1834 | const sul::dynamic_bitset bitset1(bits_to_take, value1); 1835 | const sul::dynamic_bitset bitset2(bits_to_take, value1); 1836 | 1837 | REQUIRE_FALSE(bitset1 < bitset2); 1838 | REQUIRE_FALSE(bitset2 < bitset1); 1839 | REQUIRE(bitset1 <= bitset2); 1840 | REQUIRE(bitset2 <= bitset1); 1841 | 1842 | REQUIRE_FALSE(bitset1 > bitset2); 1843 | REQUIRE_FALSE(bitset2 > bitset1); 1844 | REQUIRE(bitset1 >= bitset2); 1845 | REQUIRE(bitset2 >= bitset1); 1846 | } 1847 | 1848 | SECTION("different size and same bits") 1849 | { 1850 | const sul::dynamic_bitset bitset1(bits_to_take, value1); 1851 | sul::dynamic_bitset bitset2(bits_to_take, value1); 1852 | const bool added_value = GENERATE(true, false); 1853 | CAPTURE(added_value); 1854 | bitset2.push_back(added_value); 1855 | 1856 | REQUIRE(bitset1 < bitset2); 1857 | REQUIRE_FALSE(bitset2 < bitset1); 1858 | REQUIRE(bitset1 <= bitset2); 1859 | REQUIRE_FALSE(bitset2 <= bitset1); 1860 | 1861 | REQUIRE_FALSE(bitset1 > bitset2); 1862 | REQUIRE(bitset2 > bitset1); 1863 | REQUIRE_FALSE(bitset1 >= bitset2); 1864 | REQUIRE(bitset2 >= bitset1); 1865 | } 1866 | 1867 | SECTION("same size and different bits") 1868 | { 1869 | const sul::dynamic_bitset bitset1(bits_to_take, value1); 1870 | const sul::dynamic_bitset bitset2(bits_to_take, value2); 1871 | if(value1 < value2) 1872 | { 1873 | REQUIRE(bitset1 < bitset2); 1874 | REQUIRE_FALSE(bitset2 < bitset1); 1875 | REQUIRE(bitset1 <= bitset2); 1876 | REQUIRE_FALSE(bitset2 <= bitset1); 1877 | 1878 | REQUIRE_FALSE(bitset1 > bitset2); 1879 | REQUIRE(bitset2 > bitset1); 1880 | REQUIRE_FALSE(bitset1 >= bitset2); 1881 | REQUIRE(bitset2 >= bitset1); 1882 | } 1883 | else 1884 | { 1885 | REQUIRE(bitset2 < bitset1); 1886 | REQUIRE_FALSE(bitset1 < bitset2); 1887 | REQUIRE(bitset2 <= bitset1); 1888 | REQUIRE_FALSE(bitset1 <= bitset2); 1889 | 1890 | REQUIRE_FALSE(bitset2 > bitset1); 1891 | REQUIRE(bitset1 > bitset2); 1892 | REQUIRE_FALSE(bitset2 >= bitset1); 1893 | REQUIRE(bitset1 >= bitset2); 1894 | } 1895 | } 1896 | 1897 | SECTION("different size and different bits") 1898 | { 1899 | SECTION("difference in common blocks") 1900 | { 1901 | sul::dynamic_bitset bitset1(bits_to_take, value1); 1902 | sul::dynamic_bitset bitset2(bits_to_take, value1); 1903 | 1904 | // make bitset1 < bitset2 1905 | const size_t bit_pos = 1906 | GENERATE(take(RANDOM_VARIATIONS_TO_TEST, 1907 | random(std::numeric_limits::min(), 1908 | std::numeric_limits::max()))) 1909 | % bitset1.size(); 1910 | CAPTURE(bit_pos); 1911 | if(bitset1[bit_pos]) 1912 | { 1913 | bitset1.reset(bit_pos); 1914 | } 1915 | else 1916 | { 1917 | bitset2.set(bit_pos); 1918 | } 1919 | 1920 | // add some 0 to a bitset to have a different size 1921 | const size_t bits_to_add = 1922 | GENERATE(take(RANDOM_VARIATIONS_TO_TEST, random(0, 2 * bits_number))); 1923 | const bool bitset_to_add = GENERATE(true, false); 1924 | CAPTURE(bits_to_add, bitset_to_add); 1925 | 1926 | sul::dynamic_bitset& longest_bitset = bitset_to_add ? bitset1 : bitset2; 1927 | for(size_t i = 0; i < bits_to_add; ++i) 1928 | { 1929 | longest_bitset.push_back(false); 1930 | } 1931 | 1932 | REQUIRE(bitset1 < bitset2); 1933 | REQUIRE_FALSE(bitset2 < bitset1); 1934 | REQUIRE(bitset1 <= bitset2); 1935 | REQUIRE_FALSE(bitset2 <= bitset1); 1936 | 1937 | REQUIRE_FALSE(bitset1 > bitset2); 1938 | REQUIRE(bitset2 > bitset1); 1939 | REQUIRE_FALSE(bitset1 >= bitset2); 1940 | REQUIRE(bitset2 >= bitset1); 1941 | } 1942 | 1943 | SECTION("difference in extra blocks") 1944 | { 1945 | sul::dynamic_bitset longest_bitset(bits_to_take, value1); 1946 | sul::dynamic_bitset bitset(bits_to_take, value1); 1947 | 1948 | sul::dynamic_bitset bits_to_add = GENERATE( 1949 | take(RANDOM_VARIATIONS_TO_TEST, randomDynamicBitset(1, 2 * bits_number))); 1950 | CAPTURE(bits_to_add); 1951 | if(bits_to_add.none()) 1952 | { 1953 | bits_to_add.set(0); 1954 | } 1955 | for(size_t i = 0; i < bits_to_add.size(); ++i) 1956 | { 1957 | longest_bitset.push_back(longest_bitset[i]); 1958 | } 1959 | 1960 | REQUIRE(bitset < longest_bitset); 1961 | REQUIRE_FALSE(longest_bitset < bitset); 1962 | REQUIRE(bitset <= longest_bitset); 1963 | REQUIRE_FALSE(longest_bitset <= bitset); 1964 | 1965 | REQUIRE_FALSE(bitset > longest_bitset); 1966 | REQUIRE(longest_bitset > bitset); 1967 | REQUIRE_FALSE(bitset >= longest_bitset); 1968 | REQUIRE(longest_bitset >= bitset); 1969 | } 1970 | } 1971 | } 1972 | } 1973 | 1974 | TEMPLATE_TEST_CASE("ostream operator<<", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 1975 | { 1976 | sul::dynamic_bitset bitset = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomDynamicBitset())); 1977 | CAPTURE(bitset); 1978 | 1979 | std::stringstream sstream; 1980 | sstream << bitset; 1981 | std::string str = sstream.str(); 1982 | CAPTURE(str); 1983 | 1984 | REQUIRE(str.size() == bitset.size()); 1985 | for(size_t i = 0; i < bitset.size(); ++i) 1986 | { 1987 | CAPTURE(i); 1988 | if(bitset[bitset.size() - i - 1]) 1989 | { 1990 | REQUIRE(str[i] == '1'); 1991 | } 1992 | else 1993 | { 1994 | REQUIRE(str[i] == '0'); 1995 | } 1996 | } 1997 | } 1998 | 1999 | TEMPLATE_TEST_CASE("istream operator>>", "[dynamic_bitset]", uint16_t, uint32_t, uint64_t) 2000 | { 2001 | SECTION("invalid stream") 2002 | { 2003 | std::stringstream sstream; 2004 | sul::dynamic_bitset bitset; 2005 | sstream >> bitset; 2006 | REQUIRE(bitset.empty()); 2007 | REQUIRE(check_consistency(bitset)); 2008 | } 2009 | 2010 | SECTION("valid stream") 2011 | { 2012 | SECTION("only valid characters") 2013 | { 2014 | std::string str = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomBitsetString())); 2015 | CAPTURE(str); 2016 | 2017 | std::stringstream sstream; 2018 | sstream.str(str); 2019 | sul::dynamic_bitset bitset; 2020 | sstream >> bitset; 2021 | CAPTURE(bitset); 2022 | 2023 | REQUIRE(bitset.size() == str.size()); 2024 | for(size_t i = 0; i < str.size(); ++i) 2025 | { 2026 | CAPTURE(i); 2027 | if(str[str.size() - i - 1] == '1') 2028 | { 2029 | REQUIRE(bitset.test(i)); 2030 | } 2031 | else 2032 | { 2033 | REQUIRE_FALSE(bitset.test(i)); 2034 | } 2035 | } 2036 | REQUIRE(sstream.eof()); 2037 | REQUIRE(check_consistency(bitset)); 2038 | } 2039 | 2040 | SECTION("with invalid characters") 2041 | { 2042 | std::string str = GENERATE(take(RANDOM_VECTORS_TO_TEST, randomBitsetString())); 2043 | CAPTURE(str); 2044 | 2045 | std::stringstream sstream; 2046 | sstream << str; 2047 | sstream << 'E'; 2048 | sul::dynamic_bitset bitset; 2049 | sstream >> bitset; 2050 | CAPTURE(bitset); 2051 | 2052 | REQUIRE(bitset.size() == str.size()); 2053 | for(size_t i = 0; i < str.size(); ++i) 2054 | { 2055 | CAPTURE(i); 2056 | if(str[str.size() - i - 1] == '1') 2057 | { 2058 | REQUIRE(bitset.test(i)); 2059 | } 2060 | else 2061 | { 2062 | REQUIRE_FALSE(bitset.test(i)); 2063 | } 2064 | } 2065 | char E; 2066 | sstream >> E; 2067 | REQUIRE(E == 'E'); 2068 | sstream >> E; 2069 | REQUIRE(sstream.eof()); 2070 | REQUIRE(check_consistency(bitset)); 2071 | } 2072 | } 2073 | } 2074 | --------------------------------------------------------------------------------