├── .github └── workflows │ ├── cmake.yml │ └── coverage.yml ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── benchmark ├── CMakeLists.txt └── src │ ├── benchmark_main.cc │ ├── benchmark_main.cc_old │ ├── copy_backward_bench.hpp │ ├── copy_bench.hpp │ ├── count_bench.hpp │ ├── equal_bench.hpp │ ├── fill_bench.hpp │ ├── find_bench.hpp │ ├── move_bench.hpp │ ├── reverse_bench.hpp │ ├── rotate_bench.hpp │ ├── rw_bench.hpp │ ├── shift_bench.hpp │ ├── swap_ranges-bench.hpp │ └── transform_bench.hpp ├── example ├── CMakeLists.txt └── src │ └── example1.cpp ├── include └── bitlib │ ├── bit-algorithms │ ├── bit_algorithm.hpp │ ├── bit_algorithm_details.hpp │ ├── copy.hpp │ ├── copy_backward.hpp │ ├── count.hpp │ ├── debug_utils.hpp │ ├── equal.hpp │ ├── fill.hpp │ ├── find.hpp │ ├── libpopcnt.h │ ├── move.hpp │ ├── reverse.hpp │ ├── rotate.hpp │ ├── shift.hpp │ ├── swap_ranges.hpp │ ├── transform.hpp │ └── type_traits.hpp │ ├── bit-containers │ ├── bit-containers.hpp │ └── bit_vector.hpp │ ├── bit-iterator │ ├── bit.hpp │ ├── bit_details.hpp │ ├── bit_iterator.hpp │ ├── bit_pointer.hpp │ ├── bit_reference.hpp │ ├── bit_value.hpp │ └── linear_overload.hpp │ └── bitlib.hpp ├── profile ├── CMakeLists.txt └── src │ └── main.cpp ├── test ├── CMakeLists.txt └── src │ ├── fixtures.hpp │ ├── test-copy.cpp │ ├── test-copy_backward.cpp │ ├── test-count.cpp │ ├── test-equal.cpp │ ├── test-fill.cpp │ ├── test-find.cpp │ ├── test-move.cpp │ ├── test-reverse.cpp │ ├── test-rotate.cpp │ ├── test-shift.cpp │ ├── test-swap_ranges.cpp │ ├── test-transform.cpp │ └── vector_test.cpp └── utils └── test_utils.hpp /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths-ignore: 7 | - '**/*.md' 8 | pull_request: 9 | branches: [ master ] 10 | paths-ignore: 11 | - '**/*.md' 12 | 13 | env: 14 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 15 | BUILD_TYPE: RelWithDebInfo 16 | 17 | jobs: 18 | linux: 19 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 20 | # You can convert this to a matrix build if you need cross-platform coverage. 21 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 22 | runs-on: ${{ matrix.os }} 23 | strategy: 24 | matrix: 25 | os: [ubuntu-20.04, ubuntu-22.04] 26 | compiler: 27 | - { compiler: GNU, CC: gcc-11, CXX: g++-11 } 28 | cpp: [17, 20] 29 | 30 | steps: 31 | - name: Cancel Workflow Action 32 | uses: styfle/cancel-workflow-action@0.9.1 33 | - name: Checkout 34 | uses: actions/checkout@v2 35 | with: 36 | submodules: 'true' 37 | - name: Install requirements 38 | run: | 39 | sudo apt install build-essential manpages-dev software-properties-common 40 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test 41 | sudo apt update && sudo apt install ${{ matrix.compiler.CC }} ${{ matrix.compiler.CXX }} 42 | sudo apt-get install libgtest-dev 43 | cmake --version 44 | 45 | 46 | - name: Configure CMake 47 | env: 48 | CC: ${{ matrix.compiler.CC }} 49 | CXX: ${{ matrix.compiler.CXX }} 50 | STD: ${{ matrix.cpp }} 51 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 52 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 53 | run: cmake -Bbuild -DBITLIB_TEST=1 -DBITLIB_GTEST_REPEAT=10 -DBITLIB_EXAMPLE=1 -DCMAKE_CXX_STANDARD=${STD} 54 | 55 | 56 | - name: Build 57 | # Build your program with the given configuration 58 | run: cmake --build build -- -j 59 | 60 | - name: Test 61 | run: ctest --test-dir build -j $(nproc --all) 62 | #run: ./bin/bitlib-tests --gtest_repeat=10 --gtest_break_on_failure --gtest_brief=1 63 | 64 | - name: Run Example 65 | run: ./build/example/example1 66 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Coverage 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths-ignore: 7 | - '**/*.md' 8 | pull_request: 9 | branches: [ master ] 10 | paths-ignore: 11 | - '**/*.md' 12 | 13 | 14 | env: 15 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 16 | BUILD_TYPE: RelWithDebInfo 17 | 18 | jobs: 19 | linux: 20 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 21 | # You can convert this to a matrix build if you need cross-platform coverage. 22 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 23 | runs-on: ${{ matrix.os }} 24 | strategy: 25 | matrix: 26 | os: [ubuntu-20.04] 27 | compiler: 28 | - { compiler: GNU, CC: gcc-11, CXX: g++-11 } 29 | 30 | steps: 31 | - name: Cancel Workflow Action 32 | uses: styfle/cancel-workflow-action@0.9.1 33 | - name: Checkout 34 | uses: actions/checkout@v2 35 | with: 36 | submodules: 'true' 37 | - uses: conda-incubator/setup-miniconda@v2 38 | with: 39 | miniconda-version: "latest" 40 | activate-environment: test 41 | channels: conda-forge,defaults 42 | channel-priority: true 43 | python-version: 3.8 44 | - name: Install requirements 45 | shell: bash -l {0} 46 | run: | 47 | sudo apt install build-essential manpages-dev software-properties-common 48 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test 49 | sudo apt update && sudo apt install lcov ${{ matrix.compiler.CC }} ${{ matrix.compiler.CXX }} 50 | sudo apt install libgtest-dev 51 | conda activate test 52 | pip install --user lcov 53 | conda install cppcheck cpplint 54 | cmake --version 55 | 56 | - name: Configure CMake 57 | shell: bash -l {0} 58 | env: 59 | CC: ${{ matrix.compiler.CC }} 60 | CXX: ${{ matrix.compiler.CXX }} 61 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 62 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 63 | run: | 64 | which cpplint 65 | cmake -Bbuild -DBITLIB_TEST=1 -DBITLIB_COVERAGE=1 -DCMAKE_CXX_CPPCHECK="cppcheck;--std=c++17;--file-filter=*BitLib*" -DCMAKE_CXX_CPPLINT="cpplint;--linelength=140;" 66 | 67 | 68 | - name: Build 69 | shell: bash -l {0} 70 | # Build your program with the given configuration 71 | run: | 72 | cmake --build build -- -j 73 | #run: make bitlib-tests 74 | 75 | - name: Test 76 | shell: bash -l {0} 77 | run: ctest --test-dir build -j $(nproc --all) 78 | #run: ./bin/bitlib-tests --gtest_repeat=10 --gtest_break_on_failure --gtest_brief=1 79 | 80 | - name: Run lcov 81 | shell: bash -l {0} 82 | run: | 83 | lcov --directory build/test/CMakeFiles/bitlib-tests.dir/src --gcov-tool /usr/bin/gcov-11 --output-file lcov.out --include "*bitlib*" -c 84 | lcov -r lcov.out "*/usr/*" -r lcov.out "*_deps/*" -r lcov.out "*unit-tests*" -r lcov.out "*ext/*" -r lcov.out "*libpopcnt*" -o lcov_filtered.out 85 | 86 | #- name: Code Coverage Report 87 | #uses: romeovs/lcov-reporter-action@v0.2.11 88 | #with: 89 | #github-token: ${{ secrets.GITHUB_TOKEN }} 90 | #lcov-file: lcov_filtered.out 91 | 92 | - name: Coveralls 93 | uses: coverallsapp/github-action@master 94 | with: 95 | github-token: ${{ secrets.GITHUB_TOKEN }} 96 | path-to-lcov: lcov_filtered.out 97 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "benchmark/ext/BitArray"] 2 | path = benchmark/ext/BitArray 3 | url = https://github.com/noporpoise/BitArray.git 4 | [submodule "benchmark/ext/itsy_bitsy"] 5 | path = benchmark/ext/itsy_bitsy 6 | url = https://github.com/ThePhD/itsy_bitsy.git 7 | [submodule "benchmark/ext/dynamic_bitset"] 8 | path = benchmark/ext/dynamic_bitset 9 | url = https://github.com/pinam45/dynamic_bitset.git 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # specify the C++ standard 2 | cmake_minimum_required(VERSION 3.14) 3 | 4 | # set the project name 5 | project(Bit-Vector VERSION 0.3.0) 6 | 7 | # set output directory of builds 8 | #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 9 | 10 | # set CXX standard 11 | # Things seem to be faster in cxx 20, and there is also std::shift_* 12 | # Should fall back on 17 if 20 is not supported 13 | set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to be used") 14 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 15 | 16 | # set up linters/checkers 17 | #set(CMAKE_CXX_CPPCHECK cppcheck;--std=c++17;--file-filter=*bitlib*) 18 | #set(CMAKE_CXX_CPPLINT cpplint;--linelength=100;--filter=-whitespace;) 19 | #set(CMAKE_CXX_CLANG_TIDY 20 | #clang-tidy; 21 | #-header-filter=include/;) 22 | 23 | 24 | add_library(bitlib INTERFACE) 25 | add_library(bitlib::bitlib ALIAS bitlib) 26 | target_include_directories(bitlib INTERFACE 27 | $ 28 | $ 29 | ) 30 | 31 | 32 | # specify global compiler flags 33 | include_directories("include/" "utils/" ) 34 | 35 | # Add fmt library (useful for printing words in binary and other debugging stuff) 36 | #include(FetchContent) 37 | #FetchContent_Declare( 38 | #fmt 39 | #GIT_REPOSITORY https://github.com/fmtlib/fmt.git 40 | #GIT_TAG e57ca2e3685b160617d3d95fcd9e789c4e06ca88 #v10.1.0 41 | #) 42 | #FetchContent_MakeAvailable(fmt) 43 | 44 | 45 | option(BITLIB_HWY "Build with google highway SIMD extensions" OFF) 46 | option(BITLIB_BENCHMARK "Build bitlib benchmarks" OFF) 47 | option(BITLIB_EXAMPLE "Build bitlib examples" OFF) 48 | option(BITLIB_TEST "Build bitlib tests" OFF) 49 | option(BITLIB_PROFILE "Buid simple example for profiling" OFF) 50 | option(BITLIB_COVERAGE "Compute test coverage" OFF) 51 | 52 | if (BITLIB_HWY) 53 | add_definitions(-DBITLIB_HWY) 54 | endif() 55 | 56 | if(BITLIB_BENCHMARK) 57 | set(BENCHMARK_ENABLE_GTEST_TESTS OFF) 58 | add_subdirectory(benchmark) 59 | endif() 60 | if(BITLIB_EXAMPLE) 61 | add_subdirectory(example) 62 | endif() 63 | if(BITLIB_TEST) 64 | enable_testing() 65 | add_subdirectory(test) 66 | endif() 67 | 68 | if(BITLIB_PROFILE) 69 | add_subdirectory(profile) 70 | endif() 71 | 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Bryce Kille 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(BENCHMARK_ENABLE_GTEST_TESTS OFF) 2 | 3 | find_package(benchmark REQUIRED) 4 | 5 | # set output directory of builds 6 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 7 | 8 | # set build type 9 | set(CMAKE_BUILD_TYPE Release) 10 | 11 | # Add targets 12 | file(GLOB BENCH_SOURCES "src/*.cc") 13 | add_executable(bitlib-bench ${BENCH_SOURCES}) 14 | 15 | add_subdirectory(ext/dynamic_bitset) 16 | 17 | # specify benchmark-specific libraries 18 | include_directories( 19 | ${googlebench_SOURCE_DIR}/benchmark/include 20 | src/utils 21 | ext/BitArray 22 | ext/itsy_bitsy/include) 23 | target_link_libraries(bitlib-bench PRIVATE benchmark::benchmark -pthread ${CMAKE_CURRENT_LIST_DIR}/ext/BitArray/libbitarr.a sul::dynamic_bitset) 24 | 25 | target_compile_options(bitlib-bench PUBLIC -O3 -DNDEBUG -march=native -Wpedantic) 26 | install(TARGETS bitlib-bench DESTINATION .) 27 | -------------------------------------------------------------------------------- /benchmark/src/copy_backward_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test_utils.hpp" 3 | #include "bitlib/bitlib.hpp" 4 | 5 | auto BM_BitCopyBackward = [](benchmark::State& state, auto input) { 6 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 7 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 8 | unsigned int total_bits = std::get<2>(input); 9 | auto digits = bit::binary_digits::value; 10 | auto container_size = total_bits / digits + 1; 11 | auto bitvec1 = get_random_vec(container_size); 12 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 13 | auto bitvec2 = get_random_vec(container_size); 14 | auto first2 = bit::bit_iterator(std::begin(bitvec2)); 15 | auto start1 = 3; 16 | auto start2 = 1; 17 | auto end1 = 4; 18 | long long n = total_bits - start1 - end1; 19 | 20 | for (auto _ : state) 21 | bit::copy_backward( 22 | first1 + start1, 23 | first1 + total_bits - end1, 24 | first2 + start2 + n 25 | ); 26 | }; 27 | 28 | 29 | auto BM_BoolCopyBackward = [](benchmark::State& state, auto input) { 30 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 31 | unsigned int total_bits = std::get<2>(input); 32 | auto container_size = total_bits; 33 | container_type boolvec1 = make_random_container (container_size); 34 | container_type boolvec2 = make_random_container (container_size); 35 | auto first1 = boolvec1.begin(); 36 | auto first2 = boolvec2.begin(); 37 | 38 | auto start1 = 3; 39 | auto start2 = 1; 40 | auto end1 = 4; 41 | long long n = total_bits - start1 - end1; 42 | 43 | for (auto _ : state) 44 | std::copy_backward( 45 | first1 + start1, 46 | first1 + total_bits - end1, 47 | first2 + start2 + n 48 | ); 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /benchmark/src/copy_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test_utils.hpp" 3 | #include "bitlib/bitlib.hpp" 4 | 5 | auto BM_BitCopy = [](benchmark::State& state, auto input) { 6 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 7 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 8 | unsigned int total_bits = std::get<2>(input); 9 | auto digits = bit::binary_digits::value; 10 | auto container_size = total_bits / digits + 1; 11 | auto bitvec1 = get_random_vec(container_size); 12 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 13 | auto bitvec2 = get_random_vec(container_size); 14 | auto first2 = bit::bit_iterator(std::begin(bitvec2)); 15 | // some magic numbers 16 | auto start1 = 3; 17 | auto start2 = 1; 18 | auto end1 = 4; 19 | 20 | for (auto _ : state) 21 | bit::copy( 22 | first1 + start1, 23 | first1 + total_bits - end1, 24 | first2 + start2 25 | ); 26 | }; 27 | 28 | 29 | auto BM_BoolCopy = [](benchmark::State& state, auto input) { 30 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 31 | unsigned int total_bits = std::get<2>(input); 32 | auto container_size = total_bits; 33 | container_type boolvec1 = make_random_container (container_size); 34 | container_type boolvec2 = make_random_container (container_size); 35 | auto first1 = boolvec1.begin(); 36 | auto first2 = boolvec2.begin(); 37 | 38 | auto start1 = 3; 39 | auto start2 = 1; 40 | auto end1 = 4; 41 | 42 | for (auto _ : state) 43 | std::copy( 44 | first1 + start1, 45 | first1 + total_bits - end1, 46 | first2 + start2 47 | ); 48 | }; 49 | 50 | -------------------------------------------------------------------------------- /benchmark/src/count_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "test_utils.hpp" 4 | #include "bitlib/bit-algorithms/count.hpp" 5 | #include "bit_array.h" 6 | #include "sul/dynamic_bitset.hpp" 7 | 8 | auto BM_BitCount = [](benchmark::State& state, auto input) { 9 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 10 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 11 | unsigned int total_bits = std::get<2>(input); 12 | auto digits = bit::binary_digits::value; 13 | auto container_size = ceil(float(total_bits) / digits); 14 | container_type bitcont = make_random_container(container_size); 15 | auto first = bit::bit_iterator(std::begin(bitcont)); 16 | auto last = bit::bit_iterator(std::end(bitcont)); 17 | for (auto _ : state) { 18 | benchmark::DoNotOptimize(bit::count(first, last, bit::bit1)); 19 | benchmark::ClobberMemory(); 20 | } 21 | }; 22 | 23 | 24 | auto BM_BitArrayCount = [](benchmark::State& state, auto input) { 25 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 26 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 27 | unsigned int total_bits = std::get<2>(input); 28 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 29 | for (auto _ : state) { 30 | benchmark::DoNotOptimize(bit_array_num_bits_set(bitarr)); 31 | benchmark::ClobberMemory(); 32 | } 33 | bit_array_free(bitarr); 34 | }; 35 | 36 | auto BM_DynamicBitsetCount = [](benchmark::State& state, auto input) { 37 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 38 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 39 | unsigned int total_bits = std::get<2>(input); 40 | sul::dynamic_bitset<> bitset1(total_bits, 1); 41 | for (auto _ : state) { 42 | benchmark::DoNotOptimize(bitset1.count()); 43 | benchmark::ClobberMemory(); 44 | } 45 | }; 46 | 47 | auto BM_BoolCount = [](benchmark::State& state, auto input) { 48 | using container_type = std::vector; 49 | using num_type = typename container_type::value_type; 50 | unsigned int container_size = std::get<2>(input); 51 | container_type cont = make_random_container(container_size); 52 | auto first = cont.begin(); 53 | auto last = cont.end(); 54 | for (auto _ : state) { 55 | benchmark::DoNotOptimize(std::count(first, last, true)); 56 | benchmark::ClobberMemory(); 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /benchmark/src/equal_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test_utils.hpp" 3 | #include "bitlib/bitlib.hpp" 4 | 5 | auto BM_BitEqual = [](benchmark::State& state, auto input) { 6 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 7 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 8 | unsigned int total_bits = std::get<2>(input); 9 | auto digits = bit::binary_digits::value; 10 | auto container_size = total_bits / digits + 1; 11 | auto bitvec1 = get_random_vec(container_size); 12 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 13 | auto bitvec2 = get_random_vec(container_size); 14 | auto first2 = bit::bit_iterator(std::begin(bitvec2)); 15 | 16 | // Only really care about benchmarking when equal, since it is worst case scenario 17 | std::copy( 18 | first1 + 1, 19 | first1 + total_bits - 4, 20 | first2 + 2 21 | ); 22 | for (auto _ : state) 23 | benchmark::DoNotOptimize(bit::equal( 24 | first1 + 1, 25 | first1 + total_bits - 4, 26 | first2 + 2 27 | )); 28 | }; 29 | 30 | 31 | auto BM_BoolEqual = [](benchmark::State& state, auto input) { 32 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 33 | unsigned int total_bits = std::get<2>(input); 34 | auto container_size = total_bits; 35 | container_type boolvec1 = make_random_container (container_size); 36 | container_type boolvec2 = make_random_container (container_size); 37 | auto first1 = boolvec1.begin(); 38 | auto first2 = boolvec2.begin(); 39 | 40 | 41 | // Only really care about benchmarking when equal, since it is worst case scenario 42 | std::copy( 43 | first1 + 1, 44 | first1 + total_bits - 4, 45 | first2 + 2 46 | ); 47 | for (auto _ : state) 48 | benchmark::DoNotOptimize(std::equal( 49 | first1 + 1, 50 | first1 + total_bits - 4, 51 | first2 + 2 52 | )); 53 | }; 54 | 55 | -------------------------------------------------------------------------------- /benchmark/src/fill_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "bitlib/bit-algorithms/fill.hpp" 4 | #include "bit_array.h" 5 | #include "sul/dynamic_bitset.hpp" 6 | 7 | auto BM_BitFill = [](benchmark::State& state, auto input) { 8 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 9 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 10 | unsigned int total_bits = std::get<2>(input); 11 | auto digits = bit::binary_digits::value; 12 | auto container_size = ceil(float(total_bits) / digits); 13 | container_type bitcont = make_random_container(container_size); 14 | auto first = bit::bit_iterator(std::begin(bitcont)); 15 | auto last = bit::bit_iterator(std::end(bitcont)); 16 | for (auto _ : state) { 17 | bit::fill(first + 2, last - 3, bit::bit1); 18 | benchmark::ClobberMemory(); 19 | } 20 | }; 21 | 22 | auto BM_BitArrayFill = [](benchmark::State& state, auto input) { 23 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 24 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 25 | unsigned int total_bits = std::get<2>(input); 26 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 27 | for (auto _ : state) { 28 | bit_array_set_region(bitarr, 2, total_bits - 5); 29 | benchmark::ClobberMemory(); 30 | } 31 | bit_array_free(bitarr); 32 | }; 33 | 34 | auto BM_DynamicBitsetFill = [](benchmark::State& state, auto input) { 35 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 36 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 37 | using iterator_type = typename container_type::iterator; 38 | unsigned int total_bits = std::get<2>(input); 39 | sul::dynamic_bitset<> bitset1(total_bits, 0); 40 | for (auto _ : state) { 41 | bitset1.set(2, total_bits - 5, true); 42 | benchmark::ClobberMemory(); 43 | } 44 | }; 45 | 46 | auto BM_BoolFill = [](benchmark::State& state, auto input) { 47 | using container_type = std::vector; 48 | using num_type = typename container_type::value_type; 49 | unsigned int container_size = std::get<2>(input); 50 | container_type cont = make_random_container(container_size); 51 | auto first = cont.begin(); 52 | auto last = cont.end(); 53 | for (auto _ : state) { 54 | std::fill(first + 2, last - 3, true); 55 | benchmark::ClobberMemory(); 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /benchmark/src/find_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "bitlib/bit-algorithms/find.hpp" 4 | #include "bit_array.h" 5 | #include "sul/dynamic_bitset.hpp" 6 | 7 | auto BM_BitFind = [](benchmark::State& state, auto input) { 8 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 9 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 10 | unsigned int total_bits = std::get<2>(input); 11 | auto digits = bit::binary_digits::value; 12 | auto container_size = ceil(float(total_bits) / digits); 13 | container_type bitcont(container_size); 14 | auto first = bit::bit_iterator(std::begin(bitcont)); 15 | auto last = bit::bit_iterator(std::end(bitcont)); 16 | *(first + total_bits / 2 + 4) = bit::bit1; 17 | for (auto _ : state) { 18 | benchmark::DoNotOptimize(bit::find(first + 2, last - 3, bit::bit1)); 19 | benchmark::ClobberMemory(); 20 | } 21 | }; 22 | 23 | auto BM_BitArrayFind = [](benchmark::State& state, auto input) { 24 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 25 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 26 | unsigned int total_bits = std::get<2>(input); 27 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 28 | bit_array_set_bit(bitarr, total_bits/2 + 4); 29 | bit_index_t result; 30 | for (auto _ : state) { 31 | benchmark::DoNotOptimize(bit_array_find_first_set_bit(bitarr, &result)); 32 | benchmark::ClobberMemory(); 33 | } 34 | bit_array_free(bitarr); 35 | }; 36 | 37 | auto BM_DynamicBitsetFind = [](benchmark::State& state, auto input) { 38 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 39 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 40 | using iterator_type = typename container_type::iterator; 41 | unsigned int total_bits = std::get<2>(input); 42 | sul::dynamic_bitset<> bitset1(total_bits, 0); 43 | bitset1[total_bits / 2 + 4] = 1; 44 | for (auto _ : state) { 45 | benchmark::DoNotOptimize(bitset1.find_first()); 46 | benchmark::ClobberMemory(); 47 | } 48 | }; 49 | 50 | auto BM_BoolFind = [](benchmark::State& state, auto input) { 51 | using container_type = std::vector; 52 | using num_type = typename container_type::value_type; 53 | unsigned int container_size = std::get<2>(input); 54 | container_type cont(container_size); 55 | cont[(cont.size() / 2) + 4] = true; 56 | auto first = cont.begin(); 57 | auto last = cont.end(); 58 | for (auto _ : state) { 59 | benchmark::DoNotOptimize(std::find(first + 2, last - 3, true)); 60 | benchmark::ClobberMemory(); 61 | } 62 | }; 63 | -------------------------------------------------------------------------------- /benchmark/src/move_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test_utils.hpp" 3 | #include "bitlib/bitlib.hpp" 4 | 5 | auto BM_BitMove = [](benchmark::State& state, auto input) { 6 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 7 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 8 | unsigned int total_bits = std::get<2>(input); 9 | auto digits = bit::binary_digits::value; 10 | auto container_size = total_bits / digits + 1; 11 | auto bitvec1 = get_random_vec(container_size); 12 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 13 | auto bitvec2 = get_random_vec(container_size); 14 | auto first2 = bit::bit_iterator(std::begin(bitvec2)); 15 | auto start1 = 3; 16 | auto start2 = 1; 17 | auto end1 = 4; 18 | 19 | for (auto _ : state) 20 | bit::move( 21 | first1 + start1, 22 | first1 + total_bits - end1, 23 | first2 + start2 24 | ); 25 | }; 26 | 27 | 28 | auto BM_BoolMove = [](benchmark::State& state, auto input) { 29 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 30 | unsigned int total_bits = std::get<2>(input); 31 | auto container_size = total_bits; 32 | container_type boolvec1 = make_random_container (container_size); 33 | container_type boolvec2 = make_random_container (container_size); 34 | auto first1 = boolvec1.begin(); 35 | auto first2 = boolvec2.begin(); 36 | 37 | auto start1 = 3; 38 | auto start2 = 1; 39 | auto end1 = 4; 40 | 41 | for (auto _ : state) 42 | std::move( 43 | first1 + start1, 44 | first1 + total_bits - end1, 45 | first2 + start2 46 | ); 47 | }; 48 | 49 | -------------------------------------------------------------------------------- /benchmark/src/reverse_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "bitlib/bit-algorithms/reverse.hpp" 4 | 5 | auto BM_BitReverse = [](benchmark::State& state, auto input) { 6 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 7 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 8 | unsigned int total_bits = std::get<2>(input); 9 | auto digits = bit::binary_digits::value; 10 | auto container_size = ceil(float(total_bits) / digits); 11 | container_type bitcont = make_random_container(container_size); 12 | auto first = bit::bit_iterator(std::begin(bitcont)); 13 | auto last = bit::bit_iterator(std::end(bitcont)); 14 | for (auto _ : state) { 15 | bit::reverse(first, last); 16 | benchmark::ClobberMemory(); 17 | } 18 | }; 19 | 20 | auto BM_BitReverse_UU = [](benchmark::State& state, auto input) { 21 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 22 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 23 | unsigned int total_bits = std::get<2>(input); 24 | auto digits = bit::binary_digits::value; 25 | auto container_size = ceil(float(total_bits) / digits); 26 | container_type bitcont = make_random_container(container_size); 27 | auto first = bit::bit_iterator(std::begin(bitcont)); 28 | auto last = bit::bit_iterator(std::end(bitcont)); 29 | for (auto _ : state) { 30 | bit::reverse(first + 2, last - 3); 31 | benchmark::ClobberMemory(); 32 | } 33 | }; 34 | 35 | auto BM_BitArrayReverse = [](benchmark::State& state, auto input) { 36 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 37 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 38 | unsigned int total_bits = std::get<2>(input); 39 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 40 | for (auto _ : state) { 41 | bit_array_reverse(bitarr); 42 | benchmark::ClobberMemory(); 43 | } 44 | bit_array_free(bitarr); 45 | }; 46 | 47 | auto BM_BitArrayReverse_UU = [](benchmark::State& state, auto input) { 48 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 49 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 50 | unsigned int total_bits = std::get<2>(input); 51 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 52 | for (auto _ : state) { 53 | bit_array_reverse_region(bitarr, 2, total_bits - 5); 54 | benchmark::ClobberMemory(); 55 | } 56 | bit_array_free(bitarr); 57 | }; 58 | 59 | auto BM_BoolReverse = [](benchmark::State& state, auto input) { 60 | using container_type = std::vector; 61 | using num_type = typename container_type::value_type; 62 | unsigned int container_size = std::get<2>(input); 63 | container_type cont = make_random_container(container_size); 64 | auto first = cont.begin(); 65 | auto last = cont.end(); 66 | for (auto _ : state) { 67 | std::reverse(first, last); 68 | benchmark::ClobberMemory(); 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /benchmark/src/rotate_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "bitlib/bit-algorithms/rotate.hpp" 5 | 6 | auto BM_BitRotate = [](benchmark::State& state, auto input) { 7 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 8 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 9 | unsigned int total_bits = std::get<2>(input); 10 | auto digits = bit::binary_digits::value; 11 | auto container_size = ceil(float(total_bits) / digits); 12 | container_type bitcont = make_random_container(container_size); 13 | const int range_from = 0; 14 | const int range_to = total_bits - 1; 15 | std::random_device rand_dev; 16 | std::mt19937 generator(rand_dev()); 17 | std::uniform_int_distribution distr(range_from, range_to); 18 | auto first = bit::bit_iterator(std::begin(bitcont)); 19 | auto n_first = first + distr(generator); 20 | auto last = bit::bit_iterator(std::end(bitcont)); 21 | for (auto _ : state) { 22 | benchmark::DoNotOptimize(bit::rotate(first, n_first, last)); 23 | benchmark::ClobberMemory(); 24 | } 25 | }; 26 | 27 | 28 | auto BM_BoolRotate = [](benchmark::State& state, auto input) { 29 | using container_type = std::vector; 30 | using num_type = typename container_type::value_type; 31 | unsigned int container_size = std::get<2>(input); 32 | container_type cont = make_random_container(container_size); 33 | const int range_from = 0; 34 | const int range_to = container_size - 1; 35 | std::random_device rand_dev; 36 | std::mt19937 generator(rand_dev()); 37 | std::uniform_int_distribution distr(range_from, range_to); 38 | auto first = cont.begin(); 39 | auto n_first = first + distr(generator); 40 | auto last = cont.end(); 41 | for (auto _ : state) { 42 | benchmark::DoNotOptimize(std::rotate(first, n_first, last)); 43 | benchmark::ClobberMemory(); 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /benchmark/src/rw_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test_utils.hpp" 3 | #include "sul/dynamic_bitset.hpp" 4 | #include "bitlib/bitlib.hpp" 5 | 6 | auto BM_BitSet = [](benchmark::State& state, auto input) { 7 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 8 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 9 | unsigned int total_bits = std::get<2>(input); 10 | auto digits = bit::binary_digits::value; 11 | auto container_size = total_bits / digits + 1; 12 | auto bitvec1 = get_random_vec(container_size); 13 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 14 | 15 | for (auto _ : state) { 16 | benchmark::DoNotOptimize(first1[total_bits/2] = bit::bit1); 17 | benchmark::ClobberMemory(); 18 | } 19 | }; 20 | 21 | auto BM_BitArraySet = [](benchmark::State& state, auto input) { 22 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 23 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 24 | unsigned int total_bits = std::get<2>(input); 25 | auto digits = bit::binary_digits::value; 26 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 27 | 28 | for (auto _ : state) 29 | { 30 | bit_array_set_bit(bitarr, total_bits/2); 31 | benchmark::ClobberMemory(); 32 | } 33 | }; 34 | 35 | 36 | auto BM_DynamicBitsetSet = [](benchmark::State& state, auto input) { 37 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 38 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 39 | unsigned int total_bits = std::get<2>(input); 40 | sul::dynamic_bitset x(total_bits); 41 | container_type boolvec1 = make_random_container (total_bits); 42 | for (auto i = 0; i < total_bits; ++i) { 43 | x[i] = boolvec1[i]; 44 | } 45 | 46 | for (auto _ : state) { 47 | (x[total_bits/2] = true); 48 | benchmark::ClobberMemory(); 49 | } 50 | }; 51 | 52 | auto BM_BoolSet = [](benchmark::State& state, auto input) { 53 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 54 | unsigned int total_bits = std::get<2>(input); 55 | auto container_size = total_bits; 56 | container_type boolvec1 = make_random_container (container_size); 57 | 58 | for (auto _ : state) 59 | { 60 | benchmark::DoNotOptimize(boolvec1[container_size/2] = true); 61 | benchmark::ClobberMemory(); 62 | } 63 | }; 64 | 65 | 66 | auto BM_BitGet = [](benchmark::State& state, auto input) { 67 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 68 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 69 | unsigned int total_bits = std::get<2>(input); 70 | auto digits = bit::binary_digits::value; 71 | auto container_size = total_bits / digits + 1; 72 | auto bitvec1 = get_random_vec(container_size); 73 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 74 | 75 | for (auto _ : state) { 76 | benchmark::DoNotOptimize(first1[total_bits/2]); 77 | benchmark::ClobberMemory(); 78 | } 79 | }; 80 | 81 | auto BM_BitArrayGet = [](benchmark::State& state, auto input) { 82 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 83 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 84 | unsigned int total_bits = std::get<2>(input); 85 | auto digits = bit::binary_digits::value; 86 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 87 | 88 | for (auto _ : state) 89 | { 90 | benchmark::DoNotOptimize(bit_array_get_bit(bitarr, total_bits/2)); 91 | benchmark::ClobberMemory(); 92 | } 93 | }; 94 | 95 | 96 | auto BM_DynamicBitsetGet = [](benchmark::State& state, auto input) { 97 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 98 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 99 | unsigned int total_bits = std::get<2>(input); 100 | sul::dynamic_bitset x(total_bits); 101 | container_type boolvec1 = make_random_container (total_bits); 102 | for (auto i = 0; i < total_bits; ++i) { 103 | x[i] = boolvec1[i]; 104 | } 105 | 106 | for (auto _ : state) { 107 | benchmark::DoNotOptimize(x[total_bits/2]); 108 | benchmark::ClobberMemory(); 109 | } 110 | }; 111 | 112 | auto BM_BoolGet = [](benchmark::State& state, auto input) { 113 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 114 | unsigned int total_bits = std::get<2>(input); 115 | auto container_size = total_bits; 116 | container_type boolvec1 = make_random_container (container_size); 117 | bool x; 118 | for (auto _ : state) 119 | { 120 | benchmark::DoNotOptimize(x = boolvec1[container_size/2]); 121 | benchmark::ClobberMemory(); 122 | } 123 | }; 124 | -------------------------------------------------------------------------------- /benchmark/src/shift_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "bitlib/bitlib.hpp" 6 | #include "bit_array.h" 7 | #include "sul/dynamic_bitset.hpp" 8 | 9 | 10 | auto BM_BitShiftLeft = [](benchmark::State& state, auto input) { 11 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 12 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 13 | unsigned int total_bits = std::get<2>(input); 14 | auto digits = bit::binary_digits::value; 15 | auto container_size = ceil(float(total_bits) / digits); 16 | container_type bitcont = make_random_container(container_size); 17 | auto first = bit::bit_iterator(std::begin(bitcont)); 18 | auto last = bit::bit_iterator(std::end(bitcont)); 19 | auto n = total_bits / 2 - 1; 20 | for (auto _ : state) { 21 | benchmark::DoNotOptimize(bit::shift_left(first, last, n)); 22 | benchmark::ClobberMemory(); 23 | } 24 | }; 25 | 26 | 27 | auto BM_BitShiftLeft_UU = [](benchmark::State& state, auto input) { 28 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 29 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 30 | using iterator_type = typename container_type::iterator; 31 | unsigned int total_bits = std::get<2>(input); 32 | auto digits = bit::binary_digits::value; 33 | auto container_size = ceil(float(total_bits) / digits); 34 | container_type bitcont = make_random_container(container_size); 35 | bit::bit_iterator first = bit::bit_iterator(bitcont.begin()) + 1; 36 | bit::bit_iterator last = bit::bit_iterator(bitcont.end()) - 1; 37 | auto n = total_bits / 2 + 3; 38 | for (auto _ : state) { 39 | benchmark::DoNotOptimize(bit::shift_left(first, last, n)); 40 | benchmark::ClobberMemory(); 41 | } 42 | }; 43 | 44 | auto BM_BitArrayShiftLeft = [](benchmark::State& state, auto input) { 45 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 46 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 47 | unsigned int total_bits = std::get<2>(input); 48 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 49 | auto n = total_bits / 2 - 1; 50 | for (auto _ : state) { 51 | bit_array_shift_right(bitarr, n, 0); 52 | benchmark::ClobberMemory(); 53 | } 54 | bit_array_free(bitarr); 55 | }; 56 | 57 | 58 | auto BM_DynamicBitsetShiftLeft = [](benchmark::State& state, auto input) { 59 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 60 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 61 | using iterator_type = typename container_type::iterator; 62 | unsigned int total_bits = std::get<2>(input); 63 | sul::dynamic_bitset<> bitset1(total_bits, 1); 64 | auto n = total_bits / 2 - 1; 65 | for (auto _ : state) { 66 | bitset1 <<= n; 67 | benchmark::ClobberMemory(); 68 | } 69 | }; 70 | 71 | auto BM_BoolShiftLeft = [](benchmark::State& state, auto input) { 72 | using container_type = std::vector; 73 | using num_type = typename container_type::value_type; 74 | unsigned int container_size = std::get<2>(input); 75 | container_type cont = make_random_container(container_size); 76 | auto first = cont.begin(); 77 | auto last = cont.end(); 78 | auto n = std::distance(first, last) / 2 - 1; 79 | for (auto _ : state) { 80 | benchmark::DoNotOptimize(bit::word_shift_left(first, last, n)); 81 | benchmark::ClobberMemory(); 82 | } 83 | }; 84 | 85 | auto BM_BitShiftRight = [](benchmark::State& state, auto input) { 86 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 87 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 88 | unsigned int total_bits = std::get<2>(input); 89 | auto digits = bit::binary_digits::value; 90 | auto container_size = ceil(float(total_bits) / digits); 91 | container_type bitcont = make_random_container(container_size); 92 | auto first = bit::bit_iterator(std::begin(bitcont)); 93 | auto last = bit::bit_iterator(std::end(bitcont)); 94 | auto n = total_bits / 2 - 1; 95 | for (auto _ : state) { 96 | benchmark::DoNotOptimize(bit::shift_right(first, last, n)); 97 | benchmark::ClobberMemory(); 98 | } 99 | }; 100 | 101 | auto BM_BitShiftRight_UU = [](benchmark::State& state, auto input) { 102 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 103 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 104 | unsigned int total_bits = std::get<2>(input); 105 | auto digits = bit::binary_digits::value; 106 | auto container_size = ceil(float(total_bits) / digits); 107 | container_type bitcont = make_random_container(container_size); 108 | auto first = bit::bit_iterator(std::begin(bitcont)) + 1; 109 | auto last = bit::bit_iterator(std::end(bitcont)) - 1; 110 | auto n = total_bits / 2 + 3; 111 | for (auto _ : state) { 112 | benchmark::DoNotOptimize(bit::shift_right(first, last, n)); 113 | benchmark::ClobberMemory(); 114 | } 115 | }; 116 | 117 | auto BM_DynamicBitsetShiftRight = [](benchmark::State& state, auto input) { 118 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 119 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 120 | using iterator_type = typename container_type::iterator; 121 | unsigned int total_bits = std::get<2>(input); 122 | sul::dynamic_bitset<> bitset1(total_bits, 1); 123 | auto n = total_bits / 2 - 1; 124 | for (auto _ : state) { 125 | bitset1 >>= n; 126 | benchmark::ClobberMemory(); 127 | } 128 | }; 129 | 130 | auto BM_BitArrayShiftRight = [](benchmark::State& state, auto input) { 131 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 132 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 133 | unsigned int total_bits = std::get<2>(input); 134 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 135 | auto n = total_bits / 2 - 1; 136 | for (auto _ : state) { 137 | bit_array_shift_right(bitarr, n, 0); 138 | benchmark::ClobberMemory(); 139 | } 140 | bit_array_free(bitarr); 141 | }; 142 | 143 | auto BM_BoolShiftRight = [](benchmark::State& state, auto input) { 144 | using container_type = std::vector; 145 | using num_type = typename container_type::value_type; 146 | unsigned int container_size = std::get<2>(input); 147 | container_type cont = make_random_container(container_size); 148 | auto first = cont.begin(); 149 | auto last = cont.end(); 150 | auto n = std::distance(first, last) / 2 - 1; 151 | for (auto _ : state) { 152 | benchmark::DoNotOptimize(bit::word_shift_right(first, last, n)); 153 | benchmark::ClobberMemory(); 154 | } 155 | }; 156 | -------------------------------------------------------------------------------- /benchmark/src/swap_ranges-bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test_utils.hpp" 3 | #include "bitlib/bitlib.hpp" 4 | 5 | auto BM_BitSwapRangesAA = [](benchmark::State& state, auto input) { 6 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 7 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 8 | unsigned int total_bits = std::get<2>(input); 9 | auto digits = bit::binary_digits::value; 10 | auto container_size = total_bits / digits + 1; 11 | auto bitvec1 = get_random_vec(container_size); 12 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 13 | auto bitvec2 = get_random_vec(container_size); 14 | auto first2 = bit::bit_iterator(std::begin(bitvec2)); 15 | auto start1 = 0; 16 | auto start2 = 0; 17 | auto end1 = 0; 18 | 19 | for (auto _ : state) 20 | bit::swap_ranges( 21 | first1 + start1, 22 | first1 + total_bits - end1, 23 | first2 + start2 24 | ); 25 | }; 26 | 27 | auto BM_BitSwapRangesUU = [](benchmark::State& state, auto input) { 28 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 29 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 30 | unsigned int total_bits = std::get<2>(input); 31 | auto digits = bit::binary_digits::value; 32 | auto container_size = total_bits / digits + 1; 33 | auto bitvec1 = get_random_vec(container_size); 34 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 35 | auto bitvec2 = get_random_vec(container_size); 36 | auto first2 = bit::bit_iterator(std::begin(bitvec2)); 37 | auto start1 = 3; 38 | auto start2 = 1; 39 | auto end1 = 4; 40 | 41 | for (auto _ : state) 42 | bit::swap_ranges( 43 | first1 + start1, 44 | first1 + total_bits - end1, 45 | first2 + start2 46 | ); 47 | }; 48 | 49 | 50 | auto BM_BoolSwapRanges = [](benchmark::State& state, auto input) { 51 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 52 | unsigned int total_bits = std::get<2>(input); 53 | auto container_size = total_bits; 54 | container_type boolvec1 = make_random_container (container_size); 55 | container_type boolvec2 = make_random_container (container_size); 56 | auto first1 = boolvec1.begin(); 57 | auto first2 = boolvec2.begin(); 58 | 59 | auto start1 = 3; 60 | auto start2 = 1; 61 | auto end1 = 4; 62 | 63 | for (auto _ : state) 64 | std::swap_ranges( 65 | first1 + start1, 66 | first1 + total_bits - end1, 67 | first2 + start2 68 | ); 69 | }; 70 | 71 | -------------------------------------------------------------------------------- /benchmark/src/transform_bench.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "test_utils.hpp" 5 | #include "bitlib/bitlib.hpp" 6 | #include "sul/dynamic_bitset.hpp" 7 | #include "bit_array.h" 8 | 9 | auto BM_BitTransformUnaryAA = [](benchmark::State& state, auto input) { 10 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 11 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 12 | unsigned int total_bits = std::get<2>(input); 13 | auto digits = bit::binary_digits::value; 14 | auto container_size = total_bits / digits; 15 | auto bitvec1 = get_random_vec(container_size); 16 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 17 | auto last1 = bit::bit_iterator(std::end(bitvec1)); 18 | 19 | constexpr auto unary_op = std::bit_not(); 20 | for (auto _ : state) 21 | { 22 | benchmark::DoNotOptimize(bit::transform( 23 | first1, 24 | last1, 25 | first1, 26 | unary_op 27 | )); 28 | benchmark::ClobberMemory(); 29 | } 30 | }; 31 | 32 | auto BM_BitTransformUnaryUU = [](benchmark::State& state, auto input) { 33 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 34 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 35 | unsigned int total_bits = std::get<2>(input); 36 | auto digits = bit::binary_digits::value; 37 | auto container_size = total_bits / digits + 1; 38 | auto bitvec1 = get_random_vec(container_size); 39 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 40 | 41 | constexpr auto unary_op = std::bit_not(); 42 | for (auto _ : state) 43 | { 44 | benchmark::DoNotOptimize(bit::transform( 45 | first1 + 2, 46 | first1 + total_bits - 4, 47 | first1 + 1, 48 | unary_op 49 | )); 50 | benchmark::ClobberMemory(); 51 | } 52 | }; 53 | 54 | 55 | auto BM_BitArrayTransformUnary = [](benchmark::State& state, auto input) { 56 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 57 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 58 | unsigned int total_bits = std::get<2>(input); 59 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 60 | 61 | for (auto _ : state) 62 | { 63 | bit_array_not(bitarr, bitarr); 64 | benchmark::ClobberMemory(); 65 | } 66 | }; 67 | 68 | auto BM_DynamicBitsetTransformUnary = [](benchmark::State& state, auto input) { 69 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 70 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 71 | unsigned int total_bits = std::get<2>(input); 72 | auto digits = bit::binary_digits::value; 73 | auto container_size = total_bits / digits + 1; 74 | auto bitvec1 = get_random_vec(container_size); 75 | sul::dynamic_bitset bitset1(total_bits, 1); 76 | std::memcpy((char*)bitset1.data(), static_cast((bitvec1.data())), total_bits / 8); 77 | for (auto _ : state) { 78 | benchmark::DoNotOptimize(bitset1.flip()); 79 | benchmark::ClobberMemory(); 80 | } 81 | }; 82 | 83 | auto BM_BoolTransformUnary = [](benchmark::State& state, auto input) { 84 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 85 | unsigned int total_bits = std::get<2>(input); 86 | auto container_size = total_bits; 87 | container_type boolvec1 = make_random_container (container_size); 88 | container_type boolvec2 = make_random_container (container_size); 89 | auto first1 = boolvec1.begin(); 90 | auto first2 = boolvec2.begin(); 91 | 92 | 93 | auto unary_op = [](bool b) {return !b;}; 94 | for (auto _ : state) 95 | { 96 | std::transform( 97 | first1, 98 | first1 + total_bits, 99 | first2, 100 | unary_op 101 | ); 102 | benchmark::ClobberMemory(); 103 | } 104 | }; 105 | 106 | 107 | auto BM_BitTransformBinaryAA = [](benchmark::State& state, auto input) { 108 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 109 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 110 | unsigned int total_bits = std::get<2>(input); 111 | auto digits = bit::binary_digits::value; 112 | auto container_size = total_bits / digits + 1; 113 | auto bitvec1 = get_random_vec(container_size); 114 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 115 | auto bitvec2 = get_random_vec(container_size); 116 | auto first2 = bit::bit_iterator(std::begin(bitvec2)); 117 | 118 | constexpr auto binary_op = std::bit_and(); 119 | for (auto _ : state) 120 | { 121 | bit::transform( 122 | first1, 123 | first1 + total_bits, 124 | first2, 125 | first2, 126 | binary_op 127 | ); 128 | benchmark::ClobberMemory(); 129 | } 130 | }; 131 | 132 | auto BM_BitTransformBinaryUU = [](benchmark::State& state, auto input) { 133 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 134 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 135 | unsigned int total_bits = std::get<2>(input); 136 | auto digits = bit::binary_digits::value; 137 | auto container_size = total_bits / digits + 1; 138 | auto bitvec1 = get_random_vec(container_size); 139 | auto first1 = bit::bit_iterator(std::begin(bitvec1)); 140 | auto bitvec2 = get_random_vec(container_size); 141 | auto first2 = bit::bit_iterator(std::begin(bitvec2)); 142 | 143 | constexpr auto binary_op = std::bit_and(); 144 | for (auto _ : state) 145 | { 146 | bit::transform( 147 | first1 + 2, 148 | first1 + total_bits - 4, 149 | first2 + 3, 150 | first2 + 1, 151 | binary_op 152 | ); 153 | benchmark::ClobberMemory(); 154 | } 155 | }; 156 | 157 | auto BM_DynamicBitsetTransformBinary = [](benchmark::State& state, auto input) { 158 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 159 | using WordType = typename std::tuple_element<1, decltype(input)>::type; 160 | unsigned int total_bits = std::get<2>(input); 161 | auto digits = bit::binary_digits::value; 162 | auto container_size = total_bits / digits + 1; 163 | auto bitvec1 = get_random_vec(container_size); 164 | auto bitvec2 = get_random_vec(container_size); 165 | sul::dynamic_bitset bitset1(total_bits, 1); 166 | sul::dynamic_bitset bitset2(total_bits, 1); 167 | std::memcpy((char*)bitset1.data(), static_cast((bitvec1.data())), total_bits / 8); 168 | std::memcpy((char*)bitset2.data(), static_cast((bitvec2.data())), total_bits / 8); 169 | for (auto _ : state) { 170 | benchmark::DoNotOptimize(bitset1 &= bitset2); 171 | benchmark::ClobberMemory(); 172 | } 173 | }; 174 | 175 | auto BM_BitArrayTransformBinary = [](benchmark::State& state, auto input) { 176 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 177 | using word_type = typename std::tuple_element<1, decltype(input)>::type; 178 | unsigned int total_bits = std::get<2>(input); 179 | BIT_ARRAY* bitarr = bit_array_create(total_bits); 180 | BIT_ARRAY* bitarr2 = bit_array_create(total_bits); 181 | 182 | for (auto _ : state) 183 | { 184 | bit_array_and(bitarr, bitarr, bitarr2); 185 | benchmark::ClobberMemory(); 186 | } 187 | }; 188 | 189 | 190 | auto BM_BoolTransformBinary = [](benchmark::State& state, auto input) { 191 | using container_type = typename std::tuple_element<0, decltype(input)>::type; 192 | unsigned int total_bits = std::get<2>(input); 193 | auto container_size = total_bits; 194 | container_type boolvec1 = make_random_container (container_size); 195 | container_type boolvec2 = make_random_container (container_size); 196 | container_type boolvec3 = make_random_container (container_size); 197 | auto first1 = boolvec1.begin(); 198 | auto first2 = boolvec2.begin(); 199 | 200 | auto binary_op = [](bool a, bool b) {return a && b;}; 201 | for (auto _ : state) 202 | { 203 | std::transform( 204 | first1, 205 | first1 + total_bits, 206 | first2, 207 | first2, 208 | binary_op 209 | ); 210 | benchmark::ClobberMemory(); 211 | } 212 | }; 213 | 214 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file( GLOB EXAMPLE_SOURCES src/*.cpp ) 2 | foreach( examplesourcefile ${EXAMPLE_SOURCES} ) 3 | # Cut off the file extension and directory path 4 | get_filename_component( examplename ${examplesourcefile} NAME_WE ) 5 | add_executable( ${examplename} ${examplesourcefile} ) 6 | # Make sure YourLib is linked to each app 7 | #target_link_libraries( ${examplename} YourLib ) 8 | endforeach( examplesourcefile ${EXAMPLE_SOURCES} ) 9 | -------------------------------------------------------------------------------- /example/src/example1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "bitlib/bitlib.hpp" 4 | 5 | int main() { 6 | bit::bit_vector bv ("011111010010"); 7 | std::cout << "Original bitvec: " << bv.debug_string() << std::endl; 8 | // Original bitvec: 01111101 0010 9 | 10 | // Same behavior as std::reverse 11 | bit::reverse(bv.begin(), bv.end()); 12 | std::cout << "Reversed bitvec: " << bv.debug_string() << std::endl; 13 | // Reversed bitvec: 01001011 1110 14 | 15 | // Same behavior as std::rotate 16 | bit::rotate(bv.begin(), bv.begin() + 3, bv.end()); 17 | std::cout << "Rotated bitvec: " << bv.debug_string() << std::endl; 18 | // Rotated bitvec: 01011111 0010 19 | 20 | // Same behavior as the corresponding std::vector::push_back and std::vector::insert 21 | bv.push_back(bit::bit0); 22 | bv.insert(bv.end(), 10, bit::bit1); 23 | std::cout << "Extended bitvec: " << bv.debug_string() << std::endl; 24 | // Extended bitvec: 01011111 00100111 1111111 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/bit_algorithm.hpp: -------------------------------------------------------------------------------- 1 | // ============================= BIT_ALGORITHM ============================== // 2 | // Project: The C++ Bit Library 3 | // Name: bit_algorithm.hpp 4 | // Description: Optimized versions of algorithms for bit manipulation 5 | // Contributor(s): Vincent Reverdy [2015-2017] 6 | // Maghav Kumar [2016-2017] 7 | // Bryce Kille [2019] 8 | // Collin Gress [2019] 9 | // License: BSD 3-Clause License 10 | // ========================================================================== // 11 | #ifndef _BIT_ALGORITHM_HPP_INCLUDED 12 | #define _BIT_ALGORITHM_HPP_INCLUDED 13 | #define _Bit_Algorithm_VERSION_MAJOR @Bit_Algorithm_VERSION_MAJOR@ 14 | #define _Bit_Algorithm_VERSION_MINOR @Bit_Algorithm_VERSION_MINOR@ 15 | // ========================================================================== // 16 | 17 | 18 | 19 | // ================================ PREAMBLE ================================ // 20 | #include "debug_utils.hpp" //TODO does this belong somewhere else? 21 | #include "bit_algorithm_details.hpp" 22 | // overloads 23 | #include "bit_algorithm_details.hpp" 24 | #include "copy_backward.hpp" 25 | #include "copy.hpp" 26 | #include "count.hpp" 27 | #include "debug_utils.hpp" 28 | #include "equal.hpp" 29 | #include "fill.hpp" 30 | #include "find.hpp" 31 | #include "move.hpp" 32 | #include "reverse.hpp" 33 | #include "rotate.hpp" 34 | #include "shift.hpp" 35 | #include "swap_ranges.hpp" 36 | #include "transform.hpp" 37 | #include "type_traits.hpp" 38 | // ========================================================================== // 39 | 40 | 41 | 42 | // ========================================================================== // 43 | #endif // _BIT_ALGORITHM_HPP_INCLUDED 44 | // ========================================================================== // 45 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/copy.hpp: -------------------------------------------------------------------------------- 1 | // ================================= COPY =================================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: copy.hpp 4 | // Description: Implementation of copy, copy_if, copy_n and copy_backward 5 | // Contributor: Bryce Kille [2019] 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _COPY_HPP_INCLUDED 9 | #define _COPY_HPP_INCLUDED 10 | // ========================================================================== // 11 | 12 | 13 | 14 | // ================================ PREAMBLE ================================ // 15 | // C++ standard library 16 | #include 17 | #include 18 | // Project sources 19 | #include "bitlib/bitlib.hpp" 20 | // Third-party libraries 21 | // Miscellaneous 22 | namespace bit { 23 | // ========================================================================== // 24 | 25 | 26 | 27 | // ---------------------------- Copy Algorithms ----------------------------- // 28 | 29 | // Status: Does not work for Input/Output iterators due to distance call 30 | template 31 | constexpr bit_iterator copy(bit_iterator first, 32 | bit_iterator last, 33 | bit_iterator d_first 34 | ) 35 | { 36 | // Types and constants 37 | using dst_word_type = typename bit_iterator::word_type; 38 | using src_word_type = typename bit_iterator::word_type; 39 | using word_type = dst_word_type; 40 | using size_type = typename bit_iterator::size_type; 41 | constexpr size_type digits = binary_digits::value; 42 | 43 | // Assertions 44 | _assert_range_viability(first, last); 45 | static_assert(::std::is_same::value, "Underlying word types must be equal"); 46 | if (first == last) return d_first; 47 | 48 | 49 | // Initialization 50 | const bool is_d_first_aligned = d_first.position() == 0; 51 | size_type total_bits_to_copy = distance(first, last); 52 | size_type remaining_bits_to_copy = total_bits_to_copy; 53 | auto it = d_first.base(); 54 | 55 | 56 | // d_first is not aligned. Copy partial word to align it 57 | if (!is_d_first_aligned) { 58 | size_type partial_bits_to_copy = ::std::min( 59 | remaining_bits_to_copy, 60 | digits - d_first.position() 61 | ); 62 | *it = _bitblend( 63 | *it, 64 | static_cast( 65 | get_word(first, partial_bits_to_copy) 66 | << static_cast(d_first.position()) 67 | ), 68 | static_cast(d_first.position()), 69 | static_cast(partial_bits_to_copy) 70 | ); 71 | remaining_bits_to_copy -= partial_bits_to_copy; 72 | advance(first, partial_bits_to_copy); 73 | it++; 74 | } 75 | 76 | if (remaining_bits_to_copy > 0) { 77 | const bool is_first_aligned = first.position() == 0; 78 | //size_type words_to_copy = ::std::ceil(remaining_bits_to_copy / static_cast(digits)); 79 | // d_first will be aligned at this point 80 | if (is_first_aligned && remaining_bits_to_copy > digits) { 81 | auto N = ::std::distance(first.base(), last.base()); 82 | it = ::std::copy(first.base(), last.base(), it); 83 | first += digits * N; 84 | remaining_bits_to_copy -= digits * N; 85 | } else { 86 | // TODO benchmark if its faster to ::std::copy the entire range then shift 87 | while (remaining_bits_to_copy >= digits) { 88 | *it = get_word(first, digits); 89 | remaining_bits_to_copy -= digits; 90 | it++; 91 | advance(first, digits); 92 | } 93 | } 94 | if (remaining_bits_to_copy > 0) { 95 | *it = _bitblend( 96 | *it, 97 | get_word(first, remaining_bits_to_copy), 98 | static_cast( 99 | (static_cast(1) << remaining_bits_to_copy) - 1) 100 | ); 101 | } 102 | } 103 | return d_first + total_bits_to_copy; 104 | } 105 | // -------------------------------------------------------------------------- // 106 | 107 | 108 | 109 | // ========================================================================== // 110 | } // namespace bit 111 | #endif // _COPY_HPP_INCLUDED 112 | // ========================================================================== // 113 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/copy_backward.hpp: -------------------------------------------------------------------------------- 1 | // ============================= COPY BACKWARD ============================= // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: copy_backward.hpp 4 | // Description: bit_iterator overloads for std::copy_backward 5 | // Contributor(s): 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _COPY_BACKWARD_HPP_INCLUDED 9 | #define _COPY_BACKWARD_HPP_INCLUDED 10 | // ========================================================================== // 11 | 12 | 13 | 14 | // ================================ PREAMBLE ================================ // 15 | // C++ standard library 16 | #include 17 | #include 18 | // Project sources 19 | #include "bitlib/bitlib.hpp" 20 | // Third-party libraries 21 | // Miscellaneous 22 | namespace bit { 23 | // ========================================================================== // 24 | 25 | 26 | // Status: Does not work for Input/Output iterators due to distance call 27 | template 28 | constexpr bit_iterator copy_backward(bit_iterator first, 29 | bit_iterator last, 30 | bit_iterator d_last 31 | ) 32 | { 33 | // Types and constants 34 | using dst_word_type = typename bit_iterator::word_type; 35 | using src_word_type = typename bit_iterator::word_type; 36 | using word_type = dst_word_type; 37 | using size_type = typename bit_iterator::size_type; 38 | constexpr size_type digits = binary_digits::value; 39 | 40 | // Assertions 41 | _assert_range_viability(first, last); 42 | static_assert(::std::is_same::value, "Underlying word types must be equal"); 43 | if (first == last) return d_last; 44 | 45 | 46 | // Initialization 47 | const bool is_d_last_aligned = d_last.position() == 0; 48 | size_type total_bits_to_copy = distance(first, last); 49 | size_type remaining_bits_to_copy = total_bits_to_copy; 50 | auto it = d_last.base(); 51 | 52 | // d_last is not aligned. Copy partial word to align it 53 | if (!is_d_last_aligned) { 54 | size_type partial_bits_to_copy = ::std::min( 55 | remaining_bits_to_copy, 56 | d_last.position() 57 | ); 58 | *it = _bitblend( 59 | *it, 60 | static_cast( 61 | get_word(last - partial_bits_to_copy, partial_bits_to_copy) 62 | ) << (d_last.position() - partial_bits_to_copy), 63 | d_last.position() - partial_bits_to_copy, 64 | static_cast(partial_bits_to_copy) 65 | ); 66 | remaining_bits_to_copy -= partial_bits_to_copy; 67 | advance(last, -partial_bits_to_copy); 68 | } 69 | 70 | if (remaining_bits_to_copy > 0) { 71 | const bool is_last_aligned = last.position() == 0; 72 | //size_type words_to_copy = ::std::ceil(remaining_bits_to_copy / static_cast(digits)); 73 | // d_last will be aligned at this point 74 | if (is_last_aligned && remaining_bits_to_copy > digits) { 75 | auto N = ::std::distance(first.base(), last.base()) - 1; 76 | it = ::std::copy_backward(first.base() + 1, last.base(), it); 77 | last -= digits * N; 78 | remaining_bits_to_copy -= digits * N; 79 | it--; 80 | } else { 81 | // TODO benchmark if its faster to ::std::copy the entire range then shift 82 | while (remaining_bits_to_copy >= digits) { 83 | *(--it) = get_word(last - digits, digits); 84 | remaining_bits_to_copy -= digits; 85 | advance(last, -digits); 86 | } 87 | it--; 88 | } 89 | if (remaining_bits_to_copy > 0) { 90 | *it = _bitblend( 91 | *it, 92 | get_word(last - remaining_bits_to_copy, remaining_bits_to_copy) 93 | << (digits - remaining_bits_to_copy), 94 | digits - remaining_bits_to_copy, 95 | remaining_bits_to_copy 96 | ); 97 | remaining_bits_to_copy = 0; 98 | } 99 | } 100 | return d_last - total_bits_to_copy; 101 | } 102 | 103 | 104 | 105 | // ========================================================================== // 106 | } // namespace bit 107 | 108 | #endif // _COPY_BACKWARD_HPP_INCLUDED 109 | // ========================================================================== // 110 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/count.hpp: -------------------------------------------------------------------------------- 1 | // ================================= COUNT ================================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: bit_iterator overloads for std::count, std::count_if 4 | // License: BSD 3-Clause License 5 | // ========================================================================== // 6 | #ifndef _COUNT_HPP_INCLUDED 7 | #define _COUNT_HPP_INCLUDED 8 | // ========================================================================== // 9 | 10 | // ============================== PREAMBLE ================================== // 11 | // C++ standard library 12 | #include 13 | #include 14 | // Project sources 15 | #include "bitlib/bit-iterator/bit.hpp" 16 | #include "bitlib/bit-algorithms//libpopcnt.h" 17 | // Third-party libraries 18 | #ifdef BITLIB_HWY 19 | #include "hwy/highway.h" 20 | HWY_BEFORE_NAMESPACE(); 21 | #endif 22 | // Miscellaneous 23 | 24 | #define is_aligned(POINTER, BYTE_COUNT) \ 25 | (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0) 26 | 27 | namespace bit { 28 | 29 | #ifdef BITLIB_HWY 30 | namespace hn = hwy::HWY_NAMESPACE; 31 | #endif 32 | // ========================================================================== // 33 | 34 | template 35 | constexpr typename bit_iterator::difference_type 36 | count( 37 | bit_iterator first, 38 | bit_iterator last, 39 | bit_value value 40 | ) { 41 | // Assertions 42 | _assert_range_viability(first, last); 43 | 44 | // Types and constants 45 | using word_type = typename bit_iterator::word_type; 46 | using difference_type = typename bit_iterator::difference_type; 47 | constexpr difference_type digits = binary_digits::value; 48 | 49 | // Initialization 50 | difference_type result = 0; 51 | 52 | // Computation when bits belong to several underlying words 53 | if (first.base() != last.base()) { 54 | RandomAccessIt it = first.base(); 55 | 56 | if (first.position() != 0) { 57 | word_type first_value = *first.base() >> first.position(); 58 | result = _popcnt(first_value); 59 | ++it; 60 | } 61 | // The SIMD implementation here is actually slower than the standard 62 | //#ifdef BITLIB_HWY 63 | //// ReduceSum not implemented for unsigned char 64 | //if constexpr (digits > 8) 65 | //{ 66 | //// Align to boundary 67 | //for (; it != last.base() && !is_aligned(&(*it), 64); ++it) { 68 | //result += _popcnt(*it); 69 | //} 70 | 71 | //// SIMD 72 | //hn::ScalableTag d; 73 | //for (; std::distance(it, last.base()) >= hn::Lanes(d); it += hn::Lanes(d)) 74 | //{ 75 | //const auto popcntV = hn::PopulationCount(hn::Load(d, &*it)); 76 | //result += hn::ReduceSum(d, popcntV); 77 | //} 78 | 79 | //// Remaining 80 | //for (; it != last.base(); ++it) { 81 | //result += _popcnt(*it); 82 | //} 83 | //} else 84 | //#endif 85 | { 86 | // std:: version 87 | //result += std::transform_reduce( 88 | //it, 89 | //last.base(), 90 | //0, 91 | //std::plus{}, 92 | //[](word_type word) {return _popcnt(word); } 93 | //); 94 | 95 | // libpopcnt 96 | result += popcnt(&*it, (digits / 8) * std::distance(it, last.base())); 97 | } 98 | if (last.position() != 0) { 99 | word_type last_value = *last.base() << (digits - last.position()); 100 | result += _popcnt(last_value); 101 | } 102 | // Computation when bits belong to the same underlying word 103 | } else { 104 | result = _popcnt( 105 | _bextr(*first.base(), first.position(), last.position() 106 | - first.position()) 107 | ); 108 | } 109 | 110 | // Negates when the number of zero bits is requested 111 | if (!static_cast(value)) { 112 | result = std::distance(first, last) - result; 113 | } 114 | 115 | // Finalization 116 | return result; 117 | } 118 | 119 | } // namespace bit 120 | #ifdef BITLIB_HWY 121 | HWY_AFTER_NAMESPACE(); 122 | #endif 123 | 124 | // ========================================================================== // 125 | #endif // _COUNT_HPP_INCLUDED 126 | // ========================================================================== // 127 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/debug_utils.hpp: -------------------------------------------------------------------------------- 1 | // =========================== DEBUG_UTILS ============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: debug_utils.hpp 4 | // Description: Utilities useful for debugging 5 | // Contributor: Bryce Kille [2019] 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _DEBUG_HPP_INCLUDED 9 | #define _DEBUG_HPP_INCLUDED 10 | // ========================================================================== // 11 | 12 | 13 | 14 | // ================================ PREAMBLE ================================ // 15 | // C++ standard library 16 | #include 17 | // Project sources 18 | // Third-party libraries 19 | // Miscellaneous 20 | namespace bit { 21 | // ========================================================================== // 22 | 23 | 24 | 25 | // --------------------------- Utility Functions ---------------------------- // 26 | //template 27 | //std::string word_to_vec(T1 word) { 28 | //std::bitset::value> word_c(word); 29 | //std::string out = word_c.to_string(); 30 | //std::reverse(out.begin(), out.end()); 31 | //return out; 32 | //} 33 | // -------------------------------------------------------------------------- // 34 | 35 | 36 | 37 | // ========================================================================== // 38 | } // namespace bit 39 | #endif // _COPY_HPP_INCLUDED 40 | // ========================================================================== // 41 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/equal.hpp: -------------------------------------------------------------------------------- 1 | // ================================= EQUAL =================================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: equal.hpp 4 | // Contributor: Bryce Kille [2019] 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | #ifndef _EQUAL_HPP_INCLUDED 8 | #define _EQUAL_HPP_INCLUDED 9 | // ========================================================================== // 10 | 11 | 12 | 13 | // ================================ PREAMBLE ================================ // 14 | // C++ standard library 15 | #include 16 | #include 17 | // Project sources 18 | #include "bitlib/bitlib.hpp" 19 | // Third-party libraries 20 | // Miscellaneous 21 | namespace bit { 22 | // ========================================================================== // 23 | 24 | 25 | 26 | // ---------------------------- Equal Algorithms ----------------------------- // 27 | 28 | // Status: Does not work for Input/Output iterators due to distance call 29 | template 30 | constexpr bool equal( 31 | bit_iterator first, 32 | bit_iterator last, 33 | bit_iterator d_first 34 | ) 35 | { 36 | // Types and constants 37 | using dst_word_type = typename bit_iterator::word_type; 38 | using src_word_type = typename bit_iterator::word_type; 39 | using word_type = dst_word_type; 40 | using size_type = typename bit_iterator::size_type; 41 | constexpr size_type digits = binary_digits::value; 42 | 43 | // Assertions 44 | _assert_range_viability(first, last); 45 | static_assert(::std::is_same::value, "Underlying word types must be equal"); 46 | if (first == last) return true; 47 | 48 | // Initialization 49 | const bool is_d_first_aligned = d_first.position() == 0; 50 | size_type total_bits_to_check = distance(first, last); 51 | size_type remaining_bits_to_check = total_bits_to_check; 52 | auto it = d_first.base(); 53 | 54 | // d_first is not aligned. 55 | if (!is_d_first_aligned) { 56 | const size_type partial_bits_to_check = ::std::min( 57 | remaining_bits_to_check, 58 | digits - d_first.position()); 59 | const word_type mask = static_cast( 60 | (static_cast(1) << partial_bits_to_check) - 1 61 | ) << d_first.position(); 62 | const word_type comp = static_cast( 63 | get_word(first, partial_bits_to_check) 64 | << d_first.position()); 65 | if ((mask & *it) != (mask & comp)) { return false; } 66 | remaining_bits_to_check -= partial_bits_to_check; 67 | advance(first, partial_bits_to_check); 68 | it++; 69 | } 70 | 71 | if (remaining_bits_to_check > 0) { 72 | const bool is_first_aligned = first.position() == 0; 73 | // d_first will be aligned at this point 74 | if (is_first_aligned && remaining_bits_to_check >= digits) { 75 | auto N = ::std::distance(first.base(), last.base()); 76 | bool found_mismatch = !::std::equal(first.base(), last.base(), it); 77 | if (found_mismatch) {return false;} 78 | it += N; 79 | first += digits * N; 80 | remaining_bits_to_check -= digits * N; 81 | } else { 82 | // TODO benchmark if its faster to ::std::check the entire range then shift 83 | while (remaining_bits_to_check >= digits) { 84 | if (*it != get_word(first, digits)) {return false;} 85 | remaining_bits_to_check -= digits; 86 | it++; 87 | advance(first, digits); 88 | } 89 | } 90 | if (remaining_bits_to_check > 0) { 91 | const word_type mask = static_cast( 92 | (static_cast(1) << remaining_bits_to_check) - 1 93 | ); 94 | const word_type comp = get_word(first, remaining_bits_to_check); 95 | if ((mask & *it) != (mask & comp)) { return false; } 96 | } 97 | } 98 | return true; 99 | } 100 | // -------------------------------------------------------------------------- // 101 | 102 | 103 | 104 | // ========================================================================== // 105 | } // namespace bit 106 | #endif // _EQUAL_HPP_INCLUDED 107 | // ========================================================================== // 108 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/fill.hpp: -------------------------------------------------------------------------------- 1 | // ================================= FILL =================================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: fill.hpp 4 | // Description: bit_iterator overloads for std::fill 5 | // Contributor(s): Bryce Kille 6 | // Vincent Reverdy [2019] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _FILL_HPP_INCLUDED 10 | #define _FILL_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ============================== PREAMBLE ================================== // 16 | // C++ standard library 17 | // Project sources 18 | #include "bit_algorithm_details.hpp" 19 | // Third-party libraries 20 | #ifdef BITLIB_HWY 21 | #include "hwy/highway.h" 22 | HWY_BEFORE_NAMESPACE(); 23 | #endif 24 | // Miscellaneous 25 | #define is_aligned(POINTER, BYTE_COUNT) \ 26 | (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0) 27 | 28 | namespace bit { 29 | 30 | #ifdef BITLIB_HWY 31 | namespace hn = hwy::HWY_NAMESPACE; 32 | #endif 33 | // ========================================================================== // 34 | 35 | 36 | 37 | // Status: needs revisions 38 | template 39 | void fill(bit_iterator first, bit_iterator last, 40 | bit::bit_value bv) { 41 | // Assertions 42 | _assert_range_viability(first, last); 43 | 44 | // Types and constants 45 | using word_type = typename bit_iterator::word_type; 46 | constexpr word_type digits = binary_digits::value; 47 | 48 | // Initializations 49 | constexpr word_type ones = -1; 50 | const word_type fill_word = bv == bit0 ? 0 : ones; 51 | 52 | if (distance(first, last) == 0) { 53 | return; 54 | } 55 | if (is_within(first, last)) { 56 | write_word(fill_word, first, distance(first, last)); 57 | } else { 58 | auto it = first.base(); 59 | if (first.position() != 0) { 60 | write_word(fill_word, first, digits - first.position()); 61 | ++it; 62 | } 63 | 64 | #ifdef BITLIB_HWY 65 | // Align to 64 bit boundary 66 | for (; it != last.base() && !is_aligned(&*it, 64); it++) { 67 | *it = fill_word; 68 | } 69 | const hn::ScalableTag d; 70 | const auto fill_vec = bv == bit0 ? hn::Set(d, 0) : hn::Set(d, ones); 71 | for (; std::distance(it, last.base()) >= hn::Lanes(d); it += hn::Lanes(d)) 72 | { 73 | hn::Store(fill_vec, d, &*it); 74 | } 75 | #endif 76 | std::fill(it, last.base(), fill_word); 77 | if (last.position() != 0) { 78 | it = last.base(); 79 | write_word(fill_word, bit_iterator(&(*it)), last.position()); 80 | } 81 | } 82 | } 83 | 84 | // ========================================================================== // 85 | } // namespace bit 86 | #ifdef BITLIB_HWY 87 | HWY_AFTER_NAMESPACE(); 88 | #endif 89 | #endif // _FILL_HPP_INCLUDED 90 | // ========================================================================== // 91 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/find.hpp: -------------------------------------------------------------------------------- 1 | // ================================== FIND ================================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: bit_iterator overloads for std::find, std::find_if, std::find_if_not 4 | // License: BSD 3-Clause License 5 | // ========================================================================== // 6 | #ifndef _FIND_HPP_INCLUDED 7 | #define _FIND_HPP_INCLUDED 8 | // ========================================================================== // 9 | 10 | // ============================== PREAMBLE ================================== // 11 | // C++ standard library 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-iterator/bit.hpp" 15 | // Third-party libraries 16 | #ifdef BITLIB_HWY 17 | #include "hwy/highway.h" 18 | HWY_BEFORE_NAMESPACE(); 19 | #endif 20 | 21 | // Miscellaneous 22 | #define is_aligned(POINTER, BYTE_COUNT) \ 23 | (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0) 24 | 25 | namespace bit { 26 | 27 | #ifdef BITLIB_HWY 28 | namespace hn = hwy::HWY_NAMESPACE; 29 | #endif 30 | // ========================================================================== // 31 | 32 | 33 | template 34 | constexpr bit_iterator find( 35 | bit_iterator first, 36 | bit_iterator last, bit::bit_value bv 37 | ) { 38 | 39 | using word_type = typename bit_iterator::word_type; 40 | using size_type = typename bit_iterator::size_type; 41 | const std::size_t digits = binary_digits::value; 42 | 43 | // Initialization 44 | const bool is_first_aligned = first.position() == 0; 45 | const bool is_last_aligned = last.position() == 0; 46 | 47 | 48 | if (!is_first_aligned) { 49 | word_type shifted_first = *first.base() >> first.position(); 50 | size_type num_trailing_complementary_bits = (bv == bit0) 51 | ? _tzcnt(static_cast(~shifted_first)) 52 | : _tzcnt(static_cast(shifted_first)); 53 | if (std::next(first.base(), is_last_aligned) == last.base()) { 54 | return first + std::min(num_trailing_complementary_bits, (size_type) distance(first, last)); 55 | } else if (num_trailing_complementary_bits + first.position() < digits) { 56 | return first + num_trailing_complementary_bits; 57 | } else { 58 | first += digits - first.position(); 59 | } 60 | } 61 | 62 | // Initialization 63 | auto it = first.base(); 64 | 65 | // Waiting on github issue 66 | #ifdef BITLIB_HWY 67 | // Align the iterator 68 | while (it != last.base() && !is_aligned(&(*it), 64)) { 69 | if ((bv == bit1 && (*it == 0)) || (bv == bit0 && (*it == static_cast(-1)))) { 70 | ++it; 71 | continue; 72 | } 73 | 74 | size_type num_trailing_complementary_bits = (bv == bit0) 75 | ? _tzcnt(static_cast(~*it)) 76 | : _tzcnt(static_cast(*it)); 77 | return bit_iterator(it, (size_type) num_trailing_complementary_bits); 78 | } 79 | 80 | // SIMD 81 | hn::ScalableTag d; 82 | const auto z = hn::Zero(d); 83 | for (; std::distance(it, last.base()) >= hn::Lanes(d); it += hn::Lanes(d)) 84 | { 85 | auto v = hn::Load(d, &*it); 86 | if (bv == bit0) 87 | { 88 | v = hn::Not(v); 89 | } 90 | const auto found = hn::Gt(v, z); 91 | if (! hn::AllFalse(d, found)) 92 | { 93 | it += hn::FindKnownFirstTrue(d, found); 94 | size_type num_trailing_complementary_bits = (bv == bit0) 95 | ? _tzcnt(static_cast(~*it)) 96 | : _tzcnt(static_cast(*it)); 97 | return bit_iterator(it, (size_type) num_trailing_complementary_bits); 98 | } 99 | } 100 | #endif 101 | 102 | if (bv == bit1) { 103 | it = std::find_if(it, last.base(), [](word_type a) {return a != 0;}); 104 | } else { 105 | it = std::find_if(it, last.base(), [](word_type a) {return a != static_cast(-1);}); 106 | } 107 | 108 | if (it != last.base()) { 109 | size_type num_trailing_complementary_bits = (bv == bit0) 110 | ? _tzcnt(static_cast(~*it)) 111 | : _tzcnt(static_cast(*it)); 112 | return bit_iterator(it, (size_type) num_trailing_complementary_bits); 113 | } 114 | 115 | // Deal with any unaligned boundaries 116 | if (!is_last_aligned) { 117 | size_type num_trailing_complementary_bits = (bv == bit0) 118 | ? _tzcnt(static_cast(~*it)) 119 | : _tzcnt(static_cast(*it)); 120 | return bit_iterator(it, (size_type) std::min(num_trailing_complementary_bits, last.position())); 121 | } 122 | return last; 123 | } 124 | 125 | // ========================================================================== // 126 | } // namespace bit 127 | #ifdef BITLIB_HWY 128 | HWY_AFTER_NAMESPACE(); 129 | #endif 130 | 131 | #endif // _FIND_HPP_INCLUDED 132 | // ========================================================================== // 133 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/move.hpp: -------------------------------------------------------------------------------- 1 | // ================================== MOVE ================================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: move.hpp 4 | // Description: bit_iterator overloads for std::move 5 | // Contributor(s): 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _MOVE_HPP_INCLUDED 9 | #define _MOVE_HPP_INCLUDED 10 | // ========================================================================== // 11 | 12 | // ============================== PREAMBLE ================================== // 13 | // C++ standard library 14 | #include 15 | #include 16 | // Project sources 17 | #include "bitlib/bitlib.hpp" 18 | // Third-party libraries 19 | // Miscellaneous 20 | 21 | namespace bit { 22 | // ========================================================================== // 23 | 24 | // Status: Does not work for Input/Output iterators due to distance call 25 | template 26 | constexpr bit_iterator move(bit_iterator first, 27 | bit_iterator last, 28 | bit_iterator d_first 29 | ) 30 | { 31 | // Types and constants 32 | using dst_word_type = typename bit_iterator::word_type; 33 | using src_word_type = typename bit_iterator::word_type; 34 | using word_type = dst_word_type; 35 | using size_type = typename bit_iterator::size_type; 36 | constexpr size_type digits = binary_digits::value; 37 | 38 | // Assertions 39 | _assert_range_viability(first, last); 40 | static_assert(std::is_same::value, "Underlying word types must be equal"); 41 | if (first == last) return d_first; 42 | 43 | 44 | // Initialization 45 | const bool is_d_first_aligned = d_first.position() == 0; 46 | size_type total_bits_to_move = distance(first, last); 47 | size_type remaining_bits_to_move = total_bits_to_move; 48 | auto it = d_first.base(); 49 | 50 | 51 | // d_first is not aligned. Copy partial word to align it 52 | if (!is_d_first_aligned) { 53 | size_type partial_bits_to_move = std::min( 54 | remaining_bits_to_move, 55 | digits - d_first.position() 56 | ); 57 | *it = _bitblend( 58 | *it, 59 | static_cast( 60 | get_word(first, partial_bits_to_move) 61 | << static_cast(d_first.position()) 62 | ), 63 | static_cast(d_first.position()), 64 | static_cast(partial_bits_to_move) 65 | ); 66 | remaining_bits_to_move -= partial_bits_to_move; 67 | advance(first, partial_bits_to_move); 68 | it++; 69 | } 70 | 71 | if (remaining_bits_to_move > 0) { 72 | const bool is_first_aligned = first.position() == 0; 73 | //size_type words_to_move = std::ceil(remaining_bits_to_move / static_cast(digits)); 74 | // d_first will be aligned at this point 75 | if (is_first_aligned && remaining_bits_to_move > digits) { 76 | auto N = std::distance(first.base(), last.base()); 77 | it = std::move(first.base(), last.base(), it); 78 | first += digits * N; 79 | remaining_bits_to_move -= digits * N; 80 | } else { 81 | // TODO benchmark if its faster to std::move the entire range then shift 82 | while (remaining_bits_to_move >= digits) { 83 | *it = get_word(first, digits); 84 | remaining_bits_to_move -= digits; 85 | it++; 86 | advance(first, digits); 87 | } 88 | } 89 | if (remaining_bits_to_move > 0) { 90 | *it = _bitblend( 91 | *it, 92 | get_word(first, remaining_bits_to_move), 93 | static_cast( 94 | (static_cast(1) << remaining_bits_to_move) - 1) 95 | ); 96 | } 97 | } 98 | return d_first + total_bits_to_move; 99 | } 100 | // -------------------------------------------------------------------------- // 101 | 102 | 103 | 104 | // ========================================================================== // 105 | } // namespace bit 106 | 107 | #endif // _MOVE_HPP_INCLUDED 108 | // ========================================================================== // 109 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/reverse.hpp: -------------------------------------------------------------------------------- 1 | // =============================== reverse.hpp ================================= // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: copy.hpp 4 | // Description: Implementation of reverse 5 | // Contributor: Vincent Reverdy [2019] 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _REVERSE_HPP_INCLUDED 9 | #define _REVERSE_HPP_INCLUDED 10 | #pragma once 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | // Project sources 18 | // Third-party libraries 19 | // Miscellaneous 20 | namespace bit { 21 | // ========================================================================== // 22 | 23 | 24 | 25 | // --------------------------- Reverse Algorithms --------------------------- // 26 | // Status: complete 27 | template 28 | constexpr void reverse( 29 | bit_iterator first, 30 | bit_iterator last 31 | ) 32 | { 33 | // Assertions 34 | _assert_range_viability(first, last); 35 | 36 | // Types and constants 37 | using word_type = typename bit_iterator::word_type; 38 | using size_type = typename bit_iterator::size_type; 39 | constexpr size_type digits = binary_digits::value; 40 | 41 | // Initialization 42 | const bool is_first_aligned = first.position() == 0; 43 | const bool is_last_aligned = last.position() == 0; 44 | size_type gap = (digits - last.position()) * !is_last_aligned; 45 | auto it = first.base(); 46 | word_type first_value = {}; 47 | word_type last_value = {}; 48 | 49 | // Reverse when bit iterators are aligned 50 | if (is_first_aligned && is_last_aligned) { 51 | std::reverse(first.base(), last.base()); 52 | std::transform(it, last.base(), it, [](word_type w) { return _bitswap(w); }); 53 | // Reverse when bit iterators do not belong to the same underlying word 54 | } else if (first.base() != last.base()) { 55 | // Save first and last element 56 | first_value = *first.base(); 57 | last_value = *std::prev(last.base(), is_last_aligned); 58 | // Reverse the underlying sequence 59 | std::reverse(first.base(), std::next(last.base(), !is_last_aligned)); 60 | // Bitswap every element of the underlying sequence 61 | std::transform( 62 | first.base(), 63 | std::next(last.base(), !is_last_aligned), 64 | first.base(), 65 | [](word_type w) { return _bitswap(w); } 66 | ); 67 | // Shift the underlying sequence to the left 68 | if (first.position() < gap) { 69 | gap = gap - first.position(); 70 | shift_left( 71 | bit_iterator(first.base()), 72 | bit_iterator(std::next(last.base())), 73 | gap); 74 | it = first.base(); 75 | // Shift the underlying sequence to the right 76 | } else if (first.position() > gap) { 77 | gap = first.position() - gap; 78 | shift_right( 79 | bit_iterator(first.base()), 80 | bit_iterator(std::next(last.base(), !is_last_aligned)), 81 | gap); 82 | it = first.base(); 83 | } 84 | // Blend bits of the first element 85 | if (!is_first_aligned) { 86 | *first.base() = _bitblend( 87 | first_value, 88 | *first.base(), 89 | first.position(), 90 | digits - first.position() 91 | ); 92 | } 93 | // Blend bits of the last element 94 | if (!is_last_aligned) { 95 | *last.base() = _bitblend( 96 | *last.base(), 97 | last_value, 98 | last.position(), 99 | digits - last.position() 100 | ); 101 | } 102 | // Reverse when bit iterators belong to the same underlying word 103 | } else { 104 | *it = _bitblend( 105 | *it, 106 | _bitswap(*it >> first.position()) >> gap, 107 | first.position(), 108 | last.position() - first.position() 109 | ); 110 | } 111 | } 112 | 113 | 114 | // -------------------------------------------------------------------------- // 115 | 116 | 117 | 118 | // ========================================================================== // 119 | } // namespace bit 120 | #endif // _REVERSE_HPP_INCLUDED 121 | // ========================================================================== // 122 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/rotate.hpp: -------------------------------------------------------------------------------- 1 | // ================================= ROTATE ================================= // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: rotate.hpp 4 | // Description: bit_iterator overloads for std::rotate 5 | // Contributor(s): Bryce Kille [2019] 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _ROTATE_HPP_INCLUDED 9 | #define _ROTATE_HPP_INCLUDED 10 | // ========================================================================== // 11 | 12 | 13 | 14 | // ============================== PREAMBLE ================================== // 15 | // C++ standard library 16 | #include 17 | // Project sources 18 | #include "bit_algorithm.hpp" 19 | // Third-party libraries 20 | // Miscellaneous 21 | namespace bit { 22 | // ========================================================================== // 23 | 24 | // Rotates a range by copying [first...n_first) to the stack, then shifting 25 | // the range to the left and appending the copied section to the end. 26 | // 27 | // Note: distance(first, n_first) <= 3*digits 28 | template 29 | bit_iterator _rotate_via_copy_begin( 30 | bit_iterator first, 31 | bit_iterator n_first, 32 | bit_iterator last 33 | ) { 34 | // Types and constants 35 | using word_type = typename bit_iterator::word_type; 36 | using size_type = typename bit_iterator::size_type; 37 | constexpr size_type digits = binary_digits::value; 38 | 39 | size_type k = distance(first, n_first); 40 | assert(k <= BufferSize*digits); 41 | word_type copy_arr[BufferSize]; 42 | copy_arr[0] = *first.base(); 43 | ForwardIt it = ++first.base(); 44 | short unsigned int pos = 1; 45 | short int bits_left_to_copy = k - (digits - first.position()); 46 | while (bits_left_to_copy > 0) { 47 | copy_arr[pos++] = *it++; 48 | bits_left_to_copy -= digits; 49 | } 50 | bit_iterator ret = shift_left(first, last, k); 51 | copy( 52 | bit_iterator(copy_arr, first.position()), 53 | bit_iterator( 54 | copy_arr, 55 | first.position() 56 | ) + k, 57 | ret 58 | ); 59 | return ret; 60 | } 61 | 62 | // Rotates a range by copying [n_first, last) to the stack, then shifting 63 | // the range to the right and prepending the copied section to the beginning. 64 | // 65 | // Note: distance(n_first, last) <= 3*digits 66 | template 67 | bit_iterator _rotate_via_copy_end( 68 | bit_iterator first, 69 | bit_iterator n_first, 70 | bit_iterator last 71 | ) { 72 | // Types and constants 73 | using word_type = typename bit_iterator::word_type; 74 | using size_type = typename bit_iterator::size_type; 75 | constexpr size_type digits = binary_digits::value; 76 | 77 | size_type k = distance(n_first, last); 78 | assert(k <= BufferSize*digits); 79 | word_type copy_arr[BufferSize]; 80 | copy_arr[0] = *n_first.base(); 81 | ForwardIt it = ++n_first.base(); 82 | short unsigned int pos = 1; 83 | short int bits_left_to_copy = k - (digits - n_first.position()); 84 | while (bits_left_to_copy > 0) { 85 | copy_arr[pos++] = *it++; 86 | bits_left_to_copy -= digits; 87 | } 88 | bit_iterator ret = shift_right(first, last, k); 89 | copy( 90 | bit_iterator(copy_arr, n_first.position()), 91 | bit_iterator( 92 | copy_arr, 93 | n_first.position() 94 | ) + k, 95 | first 96 | ); 97 | return ret; 98 | } 99 | 100 | // Rotates a range using random-access iterators. Algorithm logic from the GCC 101 | // implementation 102 | template 103 | bit_iterator _rotate_via_raw( 104 | bit_iterator first, 105 | bit_iterator n_first, 106 | bit_iterator last, 107 | std::random_access_iterator_tag 108 | ) { 109 | // Types and constants 110 | using word_type = typename bit_iterator::word_type; 111 | using size_type = typename bit_iterator::size_type; 112 | using difference_type = 113 | typename bit_iterator::difference_type; 114 | constexpr difference_type digits = binary_digits::value; 115 | 116 | difference_type k = n_first - first; 117 | difference_type n = last - first; 118 | 119 | if (k == n - k) { 120 | swap_ranges(first, n_first, n_first); 121 | return n_first; 122 | } 123 | 124 | bit_iterator p = first; 125 | bit_iterator ret = first + (last - n_first); 126 | 127 | for (;;) { 128 | if (k < n - k) { 129 | if (k <= digits) { 130 | // BENCHMARK NOTE: may be better to do k <= 3*digits and use 131 | // the _rotate_via_copy method. 132 | word_type temp_word = get_word(p, k); 133 | bit_iterator temp_it = shift_left(p, p + n, k); 134 | write_word(temp_word, temp_it, k); 135 | return ret; 136 | } 137 | bit_iterator q = p + k; 138 | unsigned int full_swaps = (n - k) / k; 139 | size_type remainder = (n - k) - full_swaps*k; 140 | while (full_swaps > 0) { 141 | swap_ranges(p, q, q); 142 | p += k; 143 | q += k; 144 | --full_swaps; 145 | } 146 | swap_ranges(p, p + remainder, q); 147 | p += remainder; 148 | q += remainder; 149 | n %= k; 150 | if (n == 0) 151 | return ret; 152 | std::swap(n, k); 153 | k = n - k; 154 | } else { 155 | k = n - k; 156 | if (k <= digits) { 157 | word_type temp_word = get_word(p + n - k, k); 158 | shift_right(p, p + n, k); 159 | write_word(temp_word, p, k); 160 | return ret; 161 | } 162 | bit_iterator q = p + n; 163 | p = q - k; 164 | unsigned int full_swaps = (n - k) / k; 165 | size_type remainder = (n - k) - full_swaps*k; 166 | while (full_swaps > 0) { 167 | p -= k; 168 | q -= k; 169 | swap_ranges(p, q, q); 170 | --full_swaps; 171 | } 172 | p -= remainder; 173 | q -= remainder; 174 | swap_ranges(p, p + remainder, q); 175 | n %= k; 176 | if (n == 0) 177 | return ret; 178 | std::swap(n, k); 179 | } 180 | } 181 | } 182 | 183 | // Main function for implementing the bit overload of std::rotate. 184 | template 185 | bit_iterator rotate( 186 | bit_iterator first, 187 | bit_iterator n_first, 188 | bit_iterator last 189 | ) { 190 | // Assertions 191 | _assert_range_viability(first, n_first); 192 | _assert_range_viability(n_first, last); 193 | _assert_range_viability(first, last); 194 | //if (first == n_first) return n_first; 195 | if (first == n_first) return last; 196 | 197 | // Types and constants 198 | using word_type = typename bit_iterator::word_type; 199 | using size_type = typename bit_iterator::size_type; 200 | using difference_type = 201 | typename bit_iterator::difference_type; 202 | constexpr difference_type digits = binary_digits::value; 203 | 204 | // Initialization 205 | const bool is_first_aligned = first.position() == 0; 206 | const bool is_last_aligned = last.position() == 0; 207 | 208 | // Within the same word 209 | if (std::next(first.base(), is_last_aligned) == last.base()) { 210 | if (is_first_aligned && is_last_aligned) { 211 | *first.base() = 212 | (*first.base() >> n_first.position()) 213 | | 214 | static_cast( 215 | *first.base() << (digits - n_first.position()) 216 | ); 217 | return std::next(first, digits - n_first.position()); 218 | } else { 219 | size_type last_pos = is_last_aligned ? digits : last.position(); 220 | size_type k = n_first.position() - first.position(); 221 | size_type p = last_pos - n_first.position(); 222 | size_type d = last_pos - first.position(); 223 | 224 | word_type mask = ((1ULL << d) - 1) << first.position(); 225 | word_type rotated = *first.base() & mask; 226 | rotated = static_cast(rotated >> k) 227 | | static_cast(rotated << p); 228 | *first.base() = _bitblend( 229 | *first.base(), 230 | rotated, 231 | first.position(), 232 | d 233 | ); 234 | return std::next(first, p); 235 | } 236 | } 237 | 238 | // Single word subcases 239 | if (is_within(first, n_first)) { 240 | size_type k = distance(first, n_first); 241 | word_type temp = get_word(first, k); 242 | bit_iterator new_last = shift_left(first, last, k); 243 | write_word(temp, new_last, static_cast(k)); 244 | return new_last; 245 | } else if (is_within(n_first, last)) { 246 | size_type p = distance(n_first, last); 247 | word_type temp = get_word(n_first, p); 248 | auto new_last = shift_right(first, last, p); 249 | write_word(temp, first, static_cast(p)); 250 | return new_last; 251 | } 252 | return _rotate_via_raw( 253 | first, 254 | n_first, 255 | last, 256 | typename std::iterator_traits::iterator_category() 257 | ); 258 | } 259 | 260 | 261 | // ========================================================================== // 262 | } // namespace bit 263 | #endif // _ROTATE_HPP_INCLUDED 264 | // ========================================================================== // 265 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/shift.hpp: -------------------------------------------------------------------------------- 1 | // ================================ SHIFT ================================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: shift.hpp 4 | // Description: Implementation of shift_left and shift_right 5 | // Contributor(s): Bryce Kille [2019] 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _SHIFT_HPP_INCLUDED 9 | #define _SHIFT_HPP_INCLUDED 10 | // ========================================================================== // 11 | 12 | 13 | // ================================ PREAMBLE ================================ // 14 | // C++ standard library 15 | #include 16 | #include 17 | // Project sources 18 | // Third-party libraries 19 | #ifdef BITLIB_HWY 20 | #include "hwy/highway.h" 21 | HWY_BEFORE_NAMESPACE(); 22 | #endif 23 | // Miscellaneous 24 | #define is_aligned(POINTER, BYTE_COUNT) \ 25 | (((uintptr_t)(const void *)(POINTER)) % (BYTE_COUNT) == 0) 26 | 27 | #if __cplusplus >= 202002L 28 | #define STD_SHIFT_RIGHT(FIRST, LAST, N) std::shift_right(FIRST, LAST, N) 29 | #define STD_SHIFT_LEFT(FIRST, LAST, N) std::shift_left(FIRST, LAST, N) 30 | #else 31 | #define STD_SHIFT_RIGHT(FIRST, LAST, N) word_shift_right(FIRST, LAST, N) 32 | #define STD_SHIFT_LEFT(FIRST, LAST, N) word_shift_left(FIRST, LAST, N) 33 | #endif 34 | 35 | namespace bit { 36 | 37 | #ifdef BITLIB_HWY 38 | namespace hn = hwy::HWY_NAMESPACE; 39 | #endif 40 | // ========================================================================== // 41 | 42 | 43 | 44 | // --------------------------- Shift Algorithms ----------------------------- // 45 | 46 | template 47 | bit_iterator shift_left( 48 | bit_iterator first, 49 | bit_iterator last, 50 | typename bit_iterator::difference_type n 51 | ) { 52 | // Assertions 53 | _assert_range_viability(first, last); 54 | 55 | // Types and constants 56 | using word_type = typename bit_iterator::word_type; 57 | using size_type = typename bit_iterator::size_type; 58 | using difference_type = typename bit_iterator::difference_type; 59 | constexpr size_type digits = binary_digits::value; 60 | 61 | // Initialization 62 | auto d = bit::distance(first, last); 63 | const bool is_first_aligned = first.position() == 0; 64 | const bool is_last_aligned = last.position() == 0; 65 | auto middle = first + n; 66 | 67 | // Out of range cases 68 | if (n <= 0) return last; 69 | if (n >= d) 70 | { 71 | //bit::fill(first, last, bit::bit0); 72 | return first; 73 | } 74 | 75 | // Single word case 76 | // Triggered if all relevant bits are in first.base() 77 | if (std::next(first.base(), is_last_aligned) == last.base()) { 78 | *first.base() = _bitblend( 79 | *first.base(), 80 | (( 81 | *first.base() & ( 82 | static_cast(-1) >> ( 83 | digits - (is_last_aligned ? digits : last.position()) 84 | ) 85 | ) 86 | )) >> n, 87 | first.position(), 88 | (is_last_aligned ? digits : last.position()) - first.position() 89 | ); 90 | return first + d - n; 91 | } 92 | 93 | // Triggered if all remaining bits can fit in a word 94 | if (d - n <= digits) 95 | { 96 | word_type new_word = get_word(middle, d - n); 97 | write_word(new_word, first, d - n); 98 | return first + d - n; 99 | } 100 | // Multiple word case 101 | word_type first_value = *first.base(); 102 | word_type last_value = !is_last_aligned ? *last.base() : 0; 103 | 104 | // Align first 105 | if (!is_first_aligned) 106 | { 107 | if (first.position() >= middle.position()) 108 | { 109 | *first.base() = _bitblend( 110 | *first.base(), 111 | (*middle.base()) << (first.position() - middle.position()), 112 | first.position(), 113 | digits - first.position() 114 | ); 115 | } 116 | else 117 | { 118 | const int n1 = digits - middle.position(); 119 | const int n2 = digits - first.position() - n1; 120 | *first.base() = _bitblend( 121 | *first.base(), 122 | (*middle.base()) >> (middle.position() - first.position()), 123 | first.position(), 124 | n1 125 | ); 126 | *first.base() = _bitblend( 127 | *first.base(), 128 | (*std::next(middle.base())) << (digits - n2), 129 | first.position() + n1, 130 | n2 131 | ); 132 | } 133 | const int shifted = std::min(d - n, (digits - first.position())); 134 | first += shifted; 135 | middle += shifted; 136 | } 137 | if (middle.base() == last.base()) 138 | { 139 | const int bits_left = last.position() - middle.position(); 140 | if (bits_left > 0) 141 | { 142 | *first.base() = _bitblend( 143 | *first.base(), 144 | *middle.base() >> middle.position(), 145 | 0, 146 | bits_left 147 | ); 148 | first += bits_left; 149 | } 150 | // https://en.cppreference.com/w/cpp/algorithm/shift 151 | // "Elements that are in the original range but not the new range 152 | // are left in a valid but unspecified state." 153 | // 154 | //bit::fill(first, last, bit::bit0); 155 | return first; 156 | } 157 | 158 | // More initialization 159 | d = bit::distance(first, last); 160 | const size_type word_shifts = n / digits; 161 | const size_type offset = middle.position(); 162 | 163 | // At this point, first is aligned 164 | if (offset == 0) 165 | { 166 | first = bit::bit_iterator( 167 | STD_SHIFT_LEFT(first.base(), 168 | last.base(), 169 | word_shifts), 170 | 0 171 | ); 172 | if (!is_last_aligned) 173 | { 174 | write_word(*last.base(), first, last.position()); 175 | first += last.position(); 176 | } 177 | // https://en.cppreference.com/w/cpp/algorithm/shift 178 | // "Elements that are in the original range but not the new range 179 | // are left in a valid but unspecified state." 180 | // 181 | //bit::fill(first, last, bit::bit0); 182 | return first; 183 | } 184 | 185 | // Shift bit sequence to the lsb 186 | #ifdef BITLIB_HWY 187 | // Align to 64 bit boundary 188 | while (std::next(middle.base()) < last.base() && !is_aligned(&*first.base(), 64)) { 189 | *first.base() = _shrd(*middle.base(), *std::next(middle.base()), offset); 190 | first += digits; 191 | middle += digits; 192 | } 193 | 194 | const hn::ScalableTag d_tag; 195 | while (std::distance(middle.base(), last.base()) >= hn::Lanes(d_tag) + 10 + !is_last_aligned) 196 | { 197 | const auto v = hn::ShiftRightSame(hn::LoadU(d_tag, &*middle.base()), offset); 198 | const auto v_plus1 = hn::ShiftLeftSame(hn::LoadU(d_tag, &*(middle.base()+1)), digits - offset); 199 | hn::Store(v | v_plus1, d_tag, &*first.base()); 200 | first += hn::Lanes(d_tag)*digits; 201 | middle += hn::Lanes(d_tag)*digits; 202 | } 203 | #endif 204 | auto first_base = first.base(); 205 | auto middle_base = middle.base(); 206 | 207 | while (std::next(middle_base) < last.base()) { 208 | *first_base = _shrd(*middle_base, *std::next(middle_base), offset); 209 | first_base++; 210 | middle_base++;; 211 | } 212 | first = bit_iterator(first_base, 0); 213 | middle = bit_iterator(middle_base, middle.position()); 214 | 215 | // If middle is now penultimate word 216 | if (std::next(middle.base()) == last.base()) 217 | { 218 | *first.base() = _bitblend( 219 | *first.base(), 220 | *middle.base() >> offset, 221 | 0, 222 | digits - offset 223 | ); 224 | first += digits - offset; 225 | middle += digits - offset; 226 | } 227 | 228 | if (!is_last_aligned) 229 | { 230 | const difference_type bits_left = last.position() - middle.position(); 231 | const word_type new_word = get_word(middle, bits_left); 232 | write_word(new_word, first, bits_left); 233 | first += bits_left; 234 | } 235 | 236 | //bit::fill(first, last, bit::bit0); 237 | return first; 238 | } 239 | 240 | template 241 | bit_iterator shift_right( 242 | bit_iterator first, 243 | bit_iterator last, 244 | typename bit_iterator::difference_type n 245 | ) { 246 | // Types and constants 247 | using word_type = typename bit_iterator::word_type; 248 | using size_type = typename bit_iterator::size_type; 249 | 250 | // Initialization 251 | const bool is_first_aligned = first.position() == 0; 252 | const bool is_last_aligned = last.position() == 0; 253 | constexpr auto digits = binary_digits::value; 254 | auto d = bit::distance(first, last); 255 | bit_iterator middle = last - n; 256 | 257 | // Out of range cases 258 | if (n <= 0) return first; 259 | else if (n >= d) return last; 260 | 261 | // Single word case 262 | if (std::next(first.base(), is_last_aligned) == last.base()) { 263 | *first.base() = _bitblend( 264 | *first.base(), 265 | ( 266 | *first.base() & ( 267 | static_cast(-1) << first.position() 268 | ) 269 | ) << n, 270 | first.position(), 271 | (is_last_aligned ? digits : last.position()) - first.position() 272 | ); 273 | return first + n; 274 | } 275 | 276 | // Align last 277 | if (last.position() != 0) 278 | { 279 | const size_type bits_to_align = std::min( 280 | last.position(), 281 | bit::distance(first, middle)); 282 | const word_type word_to_write = get_word( 283 | middle - bits_to_align, 284 | bits_to_align); 285 | write_word( 286 | word_to_write, 287 | last - bits_to_align, 288 | bits_to_align); 289 | middle -= bits_to_align; 290 | last -= bits_to_align; 291 | 292 | // Nothing left to do 293 | if (middle == first) 294 | return first + n; 295 | } 296 | 297 | // More initialization 298 | const size_type word_shifts = n / digits; 299 | const size_type offset = middle.position(); 300 | 301 | // Shift bit sequence to the msb 302 | if (offset == 0) { 303 | auto new_first = bit::bit_iterator( 304 | STD_SHIFT_RIGHT( 305 | first.base(), 306 | last.base(), 307 | word_shifts), 308 | first.position() 309 | ); 310 | // https://en.cppreference.com/w/cpp/algorithm/shift 311 | // "Elements that are in the original range but not the new range 312 | // are left in a valid but unspecified state." 313 | // 314 | //bit::fill(first, new_first, bit::bit0); 315 | return first + n; 316 | } 317 | 318 | if (bit::distance(first, middle) >= digits) 319 | { 320 | #ifdef BITLIB_HWY 321 | // Align to 64 bit boundary 322 | const hn::ScalableTag d; 323 | while (std::prev(middle.base()) > first.base() && !is_aligned(&*(last.base() - hn::Lanes(d)), 64)) { 324 | *std::prev(last.base()) = _shrd(*std::prev(middle.base()), *middle.base(), offset); 325 | last -= digits; 326 | middle -= digits; 327 | } 328 | 329 | while (std::distance(first.base(), middle.base()) > hn::Lanes(d) + 1) 330 | { 331 | const auto v = hn::ShiftRightSame( 332 | hn::LoadU(d, &*(middle.base() - hn::Lanes(d))), 333 | offset); 334 | const auto v_plus1 = hn::ShiftLeftSame( 335 | hn::LoadU(d, &*(middle.base() - hn::Lanes(d) + 1)), 336 | digits - offset); 337 | hn::Store(v | v_plus1, d, &*(last.base() - hn::Lanes(d))); 338 | 339 | last -= digits * hn::Lanes(d); 340 | middle -= digits * hn::Lanes(d); 341 | } 342 | #endif 343 | 344 | auto last_base_prev = std::prev(last.base()); 345 | auto middle_base_prev = std::prev(middle.base()); 346 | 347 | while (middle_base_prev > first.base()) { 348 | *last_base_prev = _shrd(*middle_base_prev, *std::next(middle_base_prev), offset); 349 | last_base_prev--; 350 | middle_base_prev--; 351 | } 352 | 353 | if (first.position() <= middle.position()) 354 | { 355 | *last_base_prev = _shrd(*middle_base_prev, *std::next(middle_base_prev), offset); 356 | last_base_prev--; 357 | middle_base_prev--; 358 | } 359 | 360 | last = bit_iterator(std::next(last_base_prev), last.position()); 361 | middle = bit_iterator(std::next(middle_base_prev), middle.position()); 362 | } 363 | 364 | if (first.position() != middle.position()) 365 | { 366 | const size_type bits_to_align = bit::distance(first, middle); 367 | const word_type word_to_write = get_word( 368 | first, 369 | bits_to_align); 370 | write_word( 371 | word_to_write, 372 | last - bits_to_align, 373 | bits_to_align); 374 | } 375 | 376 | return first + n; 377 | } 378 | // -------------------------------------------------------------------------- // 379 | 380 | 381 | 382 | // ========================================================================== // 383 | } // namespace bit 384 | #ifdef BITLIB_HWY 385 | HWY_AFTER_NAMESPACE(); 386 | #endif 387 | #endif // _SHIFT_HPP_INCLUDED 388 | // ========================================================================== // 389 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/swap_ranges.hpp: -------------------------------------------------------------------------------- 1 | // ============================== SWAP RANGES ============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: swap_ranges.hpp 4 | // Description: bit_iterator overloads for std::swap_ranges 5 | // Contributor(s): Bryce Kille [2019] 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _SWAP_RANGES_HPP_INCLUDED 9 | #define _SWAP_RANGES_HPP_INCLUDED 10 | // ========================================================================== // 11 | 12 | 13 | 14 | // ============================== PREAMBLE ================================== // 15 | // C++ standard library 16 | // Project sources 17 | #include "bitlib/bit-iterator/bit.hpp" 18 | // Third-party libraries 19 | // Miscellaneous 20 | namespace bit { 21 | // ========================================================================== // 22 | 23 | template< class RandomAccessIt1, class RandomAccessIt2 > 24 | constexpr bit_iterator swap_ranges( 25 | bit_iterator first1, 26 | bit_iterator last1, 27 | bit_iterator first2) 28 | { 29 | // Assertions 30 | _assert_range_viability(first1, last1); 31 | 32 | // Types and constants 33 | using word_type1 = typename bit_iterator::word_type; 34 | using word_type2 = typename bit_iterator::word_type; 35 | using size_type1 = typename bit_iterator::size_type; 36 | using size_type2 = typename bit_iterator::size_type; 37 | constexpr size_type1 digits1 = binary_digits::value; 38 | constexpr size_type2 digits2 = binary_digits::value; 39 | 40 | // Initialization 41 | //const bool is_first1_aligned = first1.position() == 0; 42 | const bool is_last1_aligned = last1.position() == 0; 43 | //const bool is_first2_aligned = first2.position() == 0; 44 | RandomAccessIt1 it1 = first1.base(); 45 | RandomAccessIt2 it2 = first2.base(); 46 | 47 | if (first1 == last1) 48 | return first2; 49 | 50 | if constexpr (digits1 == digits2) { 51 | // All bits in first1 range are in 1 word 52 | if (std::next(it1, is_last1_aligned) == last1.base()) { 53 | size_type1 digits_to_copy = distance(first1, last1); 54 | if (first1.position() >= first2.position()) { 55 | _bitexch( 56 | *it1, 57 | *it2, 58 | first1.position(), 59 | first2.position(), 60 | digits_to_copy 61 | ); 62 | } else { 63 | size_type1 partial_digits_to_copy = std::min( 64 | digits_to_copy, 65 | digits2 - first2.position() 66 | ); 67 | _bitexch( 68 | *it1, 69 | *it2, 70 | first1.position(), 71 | first2.position(), 72 | partial_digits_to_copy 73 | ); 74 | if (digits_to_copy > partial_digits_to_copy) { 75 | _bitexch( 76 | *it1, 77 | *(++it2), 78 | first1.position() + partial_digits_to_copy, 79 | 0, 80 | digits_to_copy - partial_digits_to_copy 81 | ); 82 | } 83 | } 84 | return first2 + digits_to_copy; 85 | 86 | // first1 range spans multiple words, 87 | // but both ranges have same alignment 88 | } else if (first1.position() == first2.position()) { 89 | _bitexch( 90 | *it1++, 91 | *it2++, 92 | first1.position(), 93 | digits1 - first1.position() 94 | ); 95 | it2 = std::swap_ranges(it1, last1.base(), it2); 96 | it1 = last1.base(); 97 | //while (it1 != last1.base()) { 98 | //TODO std::swap_ranges 99 | //std::swap(*it1++, *it2++); 100 | //} 101 | if (!is_last1_aligned) { 102 | _bitexch( 103 | *it1, 104 | *it2, 105 | 0, 106 | last1.position() 107 | ); 108 | } 109 | return bit_iterator(it2, last1.position()); 110 | 111 | // first1 range spans mutliple words and is not aligned with first2 112 | } else { 113 | // 1. Align first1 114 | size_type1 digits_to_copy = digits1 - first1.position(); 115 | if (first1.position() > first2.position()) { 116 | _bitexch( 117 | *it1++, 118 | *it2, 119 | first1.position(), 120 | first2.position(), 121 | digits_to_copy 122 | ); 123 | } else { 124 | size_type1 partial_digits_to_copy = digits2 - first2.position(); 125 | _bitexch( 126 | *it1, 127 | *it2++, 128 | first1.position(), 129 | first2.position(), 130 | partial_digits_to_copy 131 | ); 132 | _bitexch( 133 | *it1++, 134 | *it2, 135 | first1.position() + partial_digits_to_copy, 136 | 0, 137 | digits_to_copy - partial_digits_to_copy 138 | ); 139 | } 140 | advance(first2, digits_to_copy); 141 | digits_to_copy = digits2 - first2.position(); 142 | // 2. Exchange full words 143 | while (it1 != last1.base()) { 144 | _bitexch( 145 | *it1, 146 | *it2++, 147 | 0, 148 | first2.position(), 149 | digits_to_copy 150 | ); 151 | _bitexch( 152 | *it1++, 153 | *it2, 154 | digits_to_copy, 155 | 0, 156 | digits1 - digits_to_copy 157 | ); 158 | } 159 | // Exchange last partial words 160 | if (!is_last1_aligned) { 161 | size_type2 partial_digits_to_copy = digits2 - first2.position(); 162 | if (last1.position() <= partial_digits_to_copy) { 163 | _bitexch( 164 | *it1, 165 | *it2, 166 | 0, 167 | first2.position(), 168 | last1.position() 169 | ); 170 | return bit_iterator(it2, first2.position()) + last1.position(); 171 | } else { 172 | _bitexch( 173 | *it1, 174 | *it2++, 175 | 0, 176 | first2.position(), 177 | partial_digits_to_copy 178 | ); 179 | _bitexch( 180 | *it1, 181 | *it2, 182 | partial_digits_to_copy, 183 | 0, 184 | last1.position() - partial_digits_to_copy 185 | ); 186 | return bit_iterator(it2, last1.position() - partial_digits_to_copy); 187 | } 188 | } 189 | return bit_iterator(it2, first2.position()); 190 | } 191 | } 192 | } 193 | 194 | 195 | // ========================================================================== // 196 | } // namespace bit 197 | #endif // _SWAP_RANGES_HPP_INCLUDED 198 | // ========================================================================== // 199 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/transform.hpp: -------------------------------------------------------------------------------- 1 | // =============================== TRANSFORM =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: transform.hpp 4 | // Description: bit_iterator overloads for std::transform 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | #ifndef _TRANSFORM_HPP_INCLUDED 8 | #define _TRANSFORM_HPP_INCLUDED 9 | // ========================================================================== // 10 | 11 | // ============================== PREAMBLE ================================== // 12 | // C++ standard library 13 | #include 14 | #include 15 | // Project sources 16 | #include "bitlib/bit-iterator/bit.hpp" 17 | // Third-party libraries 18 | // Miscellaneous 19 | 20 | namespace bit { 21 | // ========================================================================== // 22 | 23 | 24 | 25 | //template 26 | //constexpr bit_iterator transform( 27 | //bit_iterator first, 28 | //bit_iterator last, 29 | //bit_iterator d_first, 30 | //std::bit_or) { 31 | 32 | //return d_first; 33 | //} 34 | template 35 | constexpr bit_iterator transform( 36 | bit_iterator first, 37 | bit_iterator last, 38 | bit_iterator d_first, 39 | UnaryOperation unary_op) { 40 | using word_type = typename bit_iterator::word_type; 41 | using size_type = typename bit_iterator::size_type; 42 | constexpr size_type digits = binary_digits::value; 43 | 44 | // Assertions 45 | _assert_range_viability(first, last); 46 | if (first == last) return d_first; 47 | 48 | 49 | // Initialization 50 | const bool is_d_first_aligned = d_first.position() == 0; 51 | size_type total_bits_to_op = distance(first, last); 52 | size_type remaining_bits_to_op = total_bits_to_op; 53 | auto it = d_first.base(); 54 | 55 | // d_first is not aligned. Copy partial word to align it 56 | if (!is_d_first_aligned) { 57 | size_type partial_bits_to_op = ::std::min( 58 | remaining_bits_to_op, 59 | digits - d_first.position() 60 | ); 61 | *it = _bitblend( 62 | *it, 63 | unary_op( 64 | static_cast( 65 | get_word(first, partial_bits_to_op) 66 | << static_cast(d_first.position()) 67 | ) 68 | ), 69 | static_cast(d_first.position()), 70 | static_cast(partial_bits_to_op)); 71 | remaining_bits_to_op -= partial_bits_to_op; 72 | advance(first, partial_bits_to_op); 73 | it++; 74 | } 75 | auto firstIt = first.base(); 76 | if (remaining_bits_to_op > 0) { 77 | const bool is_first_aligned = first.position() == 0; 78 | //size_type words_to_op = ::std::ceil(remaining_bits_to_op / static_cast(digits)); 79 | // d_first will be aligned at this point 80 | if (is_first_aligned && remaining_bits_to_op > digits) { 81 | auto N = ::std::distance(firstIt, last.base()); 82 | #ifdef BITLIB_HWY 83 | if constexpr (std::is_same_v>) 84 | { 85 | // Align to 64 bit boundary 86 | for (; firstIt != last.base() && !is_aligned(&*firstIt, 64); firstIt++, it++) { 87 | *it = unary_op(*firstIt); 88 | } 89 | 90 | bool out_is_aligned = is_aligned(&*it, 64); 91 | 92 | constexpr hn::ScalableTag d; 93 | for (; std::distance(firstIt, last.base()) >= hn::Lanes(d); firstIt += hn::Lanes(d), it += hn::Lanes(d)) 94 | { 95 | const auto v = hn::Not(hn::Load(d, &*firstIt)); 96 | if (out_is_aligned) 97 | { 98 | hn::Store(v, d, &*it); 99 | } else { 100 | hn::StoreU(v, d, &*it); 101 | } 102 | } 103 | } 104 | #endif 105 | size_t std_dist = ::std::distance(firstIt, last.base()); 106 | it = std::transform(firstIt, last.base(), it, unary_op); 107 | firstIt += std_dist; 108 | first = bit_iterator(firstIt); 109 | remaining_bits_to_op -= digits * N; 110 | } else { 111 | while (remaining_bits_to_op >= digits) { 112 | *it = unary_op(get_word(first, digits)); 113 | remaining_bits_to_op -= digits; 114 | it++; 115 | advance(first, digits); 116 | } 117 | } 118 | if (remaining_bits_to_op > 0) { 119 | *it = _bitblend( 120 | *it, 121 | unary_op(get_word(first, remaining_bits_to_op)), 122 | static_cast( 123 | (static_cast(1) << remaining_bits_to_op) - 1) 124 | ); 125 | } 126 | } 127 | return d_first + total_bits_to_op; 128 | } 129 | 130 | template 131 | constexpr bit_iterator transform( 132 | bit_iterator first1, 133 | bit_iterator last1, 134 | bit_iterator first2, 135 | bit_iterator d_first, 136 | BinaryOperation binary_op) { 137 | using word_type = typename bit_iterator::word_type; 138 | using size_type = typename bit_iterator::size_type; 139 | constexpr size_type digits = binary_digits::value; 140 | 141 | // Assertions 142 | _assert_range_viability(first1, last1); 143 | if (first1 == last1) return d_first; 144 | 145 | 146 | // Initialization 147 | const bool is_d_first_aligned = d_first.position() == 0; 148 | size_type total_bits_to_op = distance(first1, last1); 149 | size_type remaining_bits_to_op = total_bits_to_op; 150 | auto it = d_first.base(); 151 | 152 | // d_first is not aligned. Copy partial word to align it 153 | if (!is_d_first_aligned) { 154 | size_type partial_bits_to_op = ::std::min( 155 | remaining_bits_to_op, 156 | digits - d_first.position() 157 | ); 158 | *it = _bitblend( 159 | *it, 160 | binary_op( 161 | static_cast( 162 | get_word(first1, partial_bits_to_op) 163 | << static_cast(d_first.position()) 164 | ), 165 | static_cast( 166 | get_word(first2, partial_bits_to_op) 167 | << static_cast(d_first.position()) 168 | ) 169 | ), 170 | static_cast(d_first.position()), 171 | static_cast(partial_bits_to_op)); 172 | remaining_bits_to_op -= partial_bits_to_op; 173 | advance(first1, partial_bits_to_op); 174 | advance(first2, partial_bits_to_op); 175 | it++; 176 | } 177 | if (remaining_bits_to_op > 0) { 178 | const bool is_first1_aligned = first1.position() == 0; 179 | const bool is_first2_aligned = first2.position() == 0; 180 | //size_type words_to_op = ::std::ceil(remaining_bits_to_op / static_cast(digits)); 181 | // d_first will be aligned at this point 182 | if (is_first1_aligned && is_first2_aligned && remaining_bits_to_op > digits) { 183 | auto N = ::std::distance(first1.base(), last1.base()); 184 | it = std::transform(first1.base(), last1.base(), first2.base(), it, binary_op); 185 | first1 += digits * N; 186 | first2 += digits * N; 187 | remaining_bits_to_op -= digits * N; 188 | } else { 189 | while (remaining_bits_to_op >= digits) { 190 | *it = binary_op( 191 | get_word(first1, digits), 192 | get_word(first2, digits)); 193 | remaining_bits_to_op -= digits; 194 | it++; 195 | advance(first1, digits); 196 | advance(first2, digits); 197 | } 198 | } 199 | if (remaining_bits_to_op > 0) { 200 | *it = _bitblend( 201 | *it, 202 | binary_op( 203 | get_word(first1, remaining_bits_to_op), 204 | get_word(first2, remaining_bits_to_op) 205 | ), 206 | static_cast( 207 | (static_cast(1) << remaining_bits_to_op) - 1) 208 | ); 209 | } 210 | } 211 | return d_first + total_bits_to_op; 212 | } 213 | 214 | //template 215 | //constexpr bit_iterator transform_word(bit_iterator first, 216 | //bit_iterator last, bit_iterator first2, 217 | //bit_iterator d_first, BinaryOperation binary_op) { 218 | //// Assertions 219 | //_assert_range_viability(first, last); 220 | 221 | //// Types and constants 222 | //using word_type1 = typename bit_iterator::word_type; 223 | //using word_type2 = typename bit_iterator::word_type; 224 | //using word_type_out = typename bit_iterator::word_type; 225 | //using size_type1 = typename bit_iterator::size_type; 226 | //using size_type2 = typename bit_iterator::size_type; 227 | //using size_type_out = typename bit_iterator::size_type; 228 | //constexpr size_type1 digits1 = binary_digits::value; 229 | //constexpr size_type2 digits2 = binary_digits::value; 230 | //constexpr size_type_out digits_out = binary_digits::value; 231 | 232 | //// This is just for now. Perhaps later we can expand to different word sizes 233 | //assert(digits1 == digits2); 234 | //assert(digits2 == digits_out); 235 | //using word_type = word_type1; 236 | //using size_type = size_type1; 237 | //constexpr size_type digits = digits1; 238 | 239 | //if (is_within(first, last)) { 240 | //word_type d = distance(first, last); 241 | //write_word( 242 | //binary_op( 243 | //get_word(first, d), 244 | //get_word(first2, d) 245 | //), 246 | //d_first, 247 | //d 248 | //); 249 | //return next(d_first, d); 250 | //} 251 | 252 | //RandomAccessIt1 it1 = first.base(); 253 | //if (first.position() != 0) { 254 | //word_type d = digits - first.position(); 255 | //write_word( 256 | //binary_op( 257 | //static_cast(*first.base() >> first.position()), 258 | //get_word(first2, d) 259 | //), 260 | //d_first, 261 | //d 262 | //); 263 | //++it1; 264 | //advance(first2, d); 265 | //advance(d_first, d); 266 | //} 267 | 268 | //while (it1 != last1.base()) { 269 | //write_word( 270 | //binary_op( 271 | //*it1++, 272 | //get_word(first2) 273 | //), 274 | //d_first, 275 | //(word_type)digits 276 | //); 277 | //advance(d_first, digits); 278 | //advance(first2, digits); 279 | //} 280 | 281 | //if (last1.position() != 0) { 282 | //write_word( 283 | //binary_op( 284 | //*it1, 285 | //get_word(first2, last1.position()) 286 | //), 287 | //d_first, 288 | //static_cast(last1.position()) 289 | //); 290 | //advance(d_first, last1.position()); 291 | //} 292 | //return d_first; 293 | //} 294 | 295 | 296 | // ========================================================================== // 297 | } // namespace bit 298 | 299 | #endif // _TRANSFORM_HPP_INCLUDED 300 | // ========================================================================== // 301 | -------------------------------------------------------------------------------- /include/bitlib/bit-algorithms/type_traits.hpp: -------------------------------------------------------------------------------- 1 | // ============================== TYPE TRAITS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: type_traits.hpp 4 | // Description: Type traits for bits 5 | // Contributor(s): Vincent Reverdy [2019] 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | #ifndef _TYPE_TRAITS_HPP_INCLUDED 9 | #define _TYPE_TRAITS_HPP_INCLUDED 10 | // ========================================================================== // 11 | 12 | 13 | 14 | // ================================ PREAMBLE ================================ // 15 | // C++ standard library 16 | // Project sources 17 | #include "bit_algorithm_details.hpp" 18 | // Third-party libraries 19 | // Miscellaneous 20 | namespace bit { 21 | // ========================================================================== // 22 | 23 | 24 | 25 | /* *********************************** BIT ********************************** */ 26 | // Bit structure definition 27 | struct bit 28 | { 29 | }; 30 | /* ************************************************************************** */ 31 | 32 | 33 | 34 | /* ********************************* IS BIT ********************************* */ 35 | // Is bit structure definition 36 | template 37 | struct is_bit 38 | : std::false_type 39 | { 40 | }; 41 | 42 | // Is bit structure specialization: bit 43 | template <> 44 | struct is_bit<::bit::bit> 45 | : std::true_type 46 | { 47 | }; 48 | 49 | // Is bit structure specialization: bit value 50 | template <> 51 | struct is_bit 52 | : std::true_type 53 | { 54 | }; 55 | 56 | // Is bit structure specialization: bit reference 57 | template 58 | struct is_bit> 59 | : std::true_type 60 | { 61 | }; 62 | 63 | // Is bit value template definition 64 | template 65 | inline constexpr bool is_bit_v = is_bit::value; 66 | /* ************************************************************************** */ 67 | 68 | 69 | 70 | /* ***************************** IS ITERATOR ******************************** */ 71 | template 72 | struct is_iterator : std::false_type {}; 73 | 74 | template 75 | struct is_iterator< 76 | T, 77 | std::void_t::value_type> 78 | > : std::true_type {}; 79 | 80 | template 81 | inline constexpr bool is_iterator_v = is_iterator::value; 82 | /* ************************************************************************** */ 83 | 84 | 85 | 86 | /* *************************** IS FORWARD ITERATOR ************************** */ 87 | template 88 | struct is_forward_iterator : std::false_type {}; 89 | 90 | template 91 | struct is_forward_iterator< 92 | T, 93 | std::enable_if_t< 94 | std::is_base_of_v< 95 | std::forward_iterator_tag, 96 | typename std::iterator_traits::iterator_category 97 | > 98 | > 99 | > : std::true_type {}; 100 | 101 | template 102 | inline constexpr bool is_forward_iterator_v = is_forward_iterator::value; 103 | /* ************************************************************************** */ 104 | 105 | 106 | 107 | /* ********************** IS BIDIRECTIONAL ITERATOR ************************* */ 108 | template 109 | struct is_bidirectional_iterator : std::false_type {}; 110 | 111 | template 112 | struct is_bidirectional_iterator< 113 | T, 114 | std::enable_if_t< 115 | std::is_base_of_v< 116 | std::bidirectional_iterator_tag, 117 | typename std::iterator_traits::iterator_category 118 | > 119 | > 120 | > : std::true_type {}; 121 | 122 | template 123 | inline constexpr bool is_bidirectional_iterator_v 124 | = is_bidirectional_iterator::value; 125 | /* ************************************************************************** */ 126 | 127 | 128 | 129 | /* *********************** IS RANDOM ACCESS ITERATOR ************************ */ 130 | template 131 | struct is_random_access_iterator : std::false_type {}; 132 | 133 | template 134 | struct is_random_access_iterator< 135 | T, 136 | std::enable_if_t< 137 | std::is_base_of_v< 138 | std::random_access_iterator_tag, 139 | typename std::iterator_traits::iterator_category 140 | > 141 | > 142 | > : std::true_type {}; 143 | 144 | template 145 | inline constexpr bool is_random_access_iterator_v = 146 | is_random_access_iterator::value; 147 | /* ************************************************************************** */ 148 | 149 | 150 | 151 | /* *************************** IS INPUT ITERATOR **************************** */ 152 | template 153 | struct is_input_iterator : std::false_type {}; 154 | 155 | template 156 | struct is_input_iterator< 157 | T, 158 | std::enable_if_t< 159 | std::is_base_of_v< 160 | std::input_iterator_tag, 161 | typename std::iterator_traits::iterator_category 162 | > 163 | > 164 | > : std::true_type {}; 165 | 166 | template 167 | inline constexpr bool is_input_iterator_v = is_input_iterator::value; 168 | /* ************************************************************************** */ 169 | 170 | 171 | 172 | /* ************************** IS OUTPUT ITERATOR **************************** */ 173 | template 174 | struct is_output_iterator : std::false_type {}; 175 | 176 | template 177 | struct is_output_iterator< 178 | T, 179 | std::enable_if_t< 180 | std::is_base_of_v< 181 | std::output_iterator_tag, 182 | typename std::iterator_traits::iterator_category 183 | > 184 | > 185 | > : std::true_type {}; 186 | 187 | template 188 | inline constexpr bool is_output_iterator_v = is_output_iterator::value; 189 | /* ************************************************************************** */ 190 | 191 | 192 | 193 | // ========================================================================== // 194 | } // namespace bit 195 | #endif // _TYPE_TRAITS_HPP_INCLUDED 196 | // ========================================================================== // 197 | 198 | -------------------------------------------------------------------------------- /include/bitlib/bit-containers/bit-containers.hpp: -------------------------------------------------------------------------------- 1 | // =============================== NEEDS NAME (: ================================ // 2 | // Project: The Bit Algorithms Library 3 | // Name: bit-containers.hpp 4 | // Description: Brings in all of the container headers together 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | #ifndef _BIT_CONTAINERS_HPP_INCLUDED 8 | #define _BIT_CONTAINERS_HPP_INCLUDED 9 | // ============================== PREAMBLE ================================== // 10 | #include "bit_vector.hpp" 11 | // ========================================================================== // 12 | #endif 13 | -------------------------------------------------------------------------------- /include/bitlib/bit-iterator/bit.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | */ 4 | 5 | // ================================== BIT =================================== // 6 | // Project: The C++ Bit Library 7 | // Name: bit.hpp 8 | // Description: Includes the whole C++ bit library 9 | // Creator: Vincent Reverdy 10 | // Contributor(s): Vincent Reverdy [2015-2017] 11 | // License: BSD 3-Clause License 12 | // ========================================================================== // 13 | #ifndef _BIT_HPP_INCLUDED 14 | #define _BIT_HPP_INCLUDED 15 | // ========================================================================== // 16 | 17 | 18 | 19 | // ================================ PREAMBLE ================================ // 20 | // C++ standard library 21 | // Project sources 22 | #include "bit_details.hpp" 23 | #include "bit_value.hpp" 24 | #include "bit_reference.hpp" 25 | #include "bit_pointer.hpp" 26 | #include "bit_iterator.hpp" 27 | // Third-party libraries 28 | // Miscellaneous 29 | // ========================================================================== // 30 | 31 | 32 | 33 | // ========================================================================== // 34 | #endif // _BIT_HPP_INCLUDED 35 | // ========================================================================== // 36 | -------------------------------------------------------------------------------- /include/bitlib/bit-iterator/linear_overload.hpp: -------------------------------------------------------------------------------- 1 | // ============================ LINEAR OVERLOAD ============================= // 2 | // Project: The C++ Bit Library 3 | // Name: linear_overload.hpp 4 | // Description: Utilities to invoke the first valid call of an overload set 5 | // Creator: Vincent Reverdy 6 | // Contributor(s): Vincent Reverdy [2015-2017] 7 | // License: BSD 3-Clause License 8 | // ========================================================================== // 9 | #ifndef _LINEAR_OVERLOAD_HPP_INCLUDED 10 | #define _LINEAR_OVERLOAD_HPP_INCLUDED 11 | // ========================================================================== // 12 | 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | #include 18 | #include 19 | #include 20 | // Project sources 21 | // Third-party libraries 22 | // Miscellaneous 23 | namespace bit { 24 | // ========================================================================== // 25 | 26 | 27 | 28 | /* **************************** LINEAR OVERLOAD ***************************** */ 29 | // Linear overload class definition 30 | template 31 | class linear_overload 32 | { 33 | // Types 34 | public: 35 | using tuple = std::tuple; 36 | 37 | // Lifecycle 38 | public: 39 | template 40 | explicit constexpr linear_overload(G&&... g); 41 | 42 | // Access 43 | public: 44 | template 45 | decltype(auto) get() noexcept; 46 | template 47 | constexpr decltype(auto) get() const noexcept; 48 | template 49 | decltype(auto) get() noexcept; 50 | template 51 | constexpr decltype(auto) get() const noexcept; 52 | 53 | // Capacity 54 | public: 55 | static constexpr bool empty() noexcept; 56 | static constexpr std::size_t size() noexcept; 57 | static constexpr std::size_t max_size() noexcept; 58 | 59 | // Call 60 | public: 61 | template < 62 | std::size_t N = 0, 63 | class... Args, 64 | class = typename std::enable_if= size()>::type 65 | > 66 | void operator()(Args&&...); 67 | template < 68 | std::size_t N = 0, 69 | class = typename std::enable_if::type, 70 | class = decltype(std::get(std::declval())()) 71 | > 72 | decltype(auto) operator()(); 73 | template < 74 | std::size_t N = 0, 75 | class Arg, 76 | class... Args, 77 | class = typename std::enable_if::type, 78 | class = decltype(std::get(std::declval())( 79 | std::declval(), 80 | std::declval()... 81 | )) 82 | > 83 | decltype(auto) operator()(Arg&& arg, Args&&... args); 84 | template < 85 | std::size_t N = 0, 86 | class... Args, 87 | class = typename std::enable_if::type 88 | > 89 | decltype(auto) operator()(Args&&... args); 90 | 91 | // Implementation details: data members 92 | private: 93 | tuple _f; 94 | 95 | // Maker 96 | public: 97 | template 98 | friend constexpr linear_overload overload_linearly(G&&... g); 99 | }; 100 | /* ************************************************************************** */ 101 | 102 | 103 | 104 | // ----------------------- LINEAR OVERLOAD: LIFECYCLE ----------------------- // 105 | // Explicitly constructs a linear overload from a list of functions 106 | template 107 | template 108 | constexpr linear_overload::linear_overload( 109 | G&&... g 110 | ) 111 | : _f{std::forward(g)...} 112 | { 113 | } 114 | // -------------------------------------------------------------------------- // 115 | 116 | 117 | 118 | // ------------------------ LINEAR OVERLOAD: ACCESS ------------------------- // 119 | // Gets the i-th function of the linear overload 120 | template 121 | template 122 | decltype(auto) linear_overload::get( 123 | ) noexcept 124 | { 125 | return std::get(_f); 126 | } 127 | 128 | // Gets the i-th function of the immutable linear overload 129 | template 130 | template 131 | constexpr decltype(auto) linear_overload::get( 132 | ) const noexcept 133 | { 134 | return std::get(_f); 135 | } 136 | 137 | // Gets the function of the given type from the linear overload 138 | template 139 | template 140 | decltype(auto) linear_overload::get() noexcept 141 | { 142 | return std::get(_f); 143 | } 144 | 145 | // Gets the function of the given type from the immutable linear overload 146 | template 147 | template 148 | constexpr decltype(auto) linear_overload::get( 149 | ) const noexcept 150 | { 151 | return std::get(_f); 152 | } 153 | // -------------------------------------------------------------------------- // 154 | 155 | 156 | 157 | // ----------------------- LINEAR OVERLOAD: CAPACITY ------------------------ // 158 | // Checks whether the linear overload is empty 159 | template 160 | constexpr bool linear_overload::empty( 161 | ) noexcept 162 | { 163 | return std::tuple_size::value == 0; 164 | } 165 | 166 | // Returns the number of functions in the linear overload 167 | template 168 | constexpr std::size_t linear_overload::size( 169 | ) noexcept 170 | { 171 | return std::tuple_size::value; 172 | } 173 | 174 | // Returns the maximum possible number of functions in the linear overload 175 | template 176 | constexpr std::size_t linear_overload::max_size( 177 | ) noexcept 178 | { 179 | return std::tuple_size::value; 180 | } 181 | // -------------------------------------------------------------------------- // 182 | 183 | 184 | 185 | // ------------------------- LINEAR OVERLOAD: CALL -------------------------- // 186 | // Calls the linear overload with the provided arguments: no valid overload 187 | template 188 | template 189 | void linear_overload::operator()( 190 | Args&&... 191 | ) 192 | { 193 | } 194 | 195 | // Calls the linear overload with the provided arguments: no argument 196 | template 197 | template 198 | decltype(auto) linear_overload::operator()( 199 | ) 200 | { 201 | return std::get(_f)(); 202 | } 203 | 204 | // Calls the linear overload with the provided arguments: valid call 205 | template 206 | template 207 | decltype(auto) linear_overload::operator()( 208 | Arg&& arg, 209 | Args&&... args 210 | ) 211 | { 212 | return std::get(_f)(std::forward(arg), std::forward(args)...); 213 | } 214 | 215 | // Calls the linear overload with the provided arguments: invalid call 216 | template 217 | template 218 | decltype(auto) linear_overload::operator()( 219 | Args&&... args 220 | ) 221 | { 222 | return operator()(std::forward(args)...); 223 | } 224 | // -------------------------------------------------------------------------- // 225 | 226 | 227 | 228 | // ------------------------- LINEAR OVERLOAD: MAKER ------------------------- // 229 | // Builds a linear overload from a list of functions 230 | template 231 | constexpr linear_overload overload_linearly(G&&... g) 232 | { 233 | return linear_overload(std::forward(g)...); 234 | } 235 | // -------------------------------------------------------------------------- // 236 | 237 | 238 | 239 | // ========================================================================== // 240 | } // namespace bit 241 | #endif // _LINEAR_OVERLOAD_HPP_INCLUDED 242 | // ========================================================================== // 243 | -------------------------------------------------------------------------------- /include/bitlib/bitlib.hpp: -------------------------------------------------------------------------------- 1 | // ================================= BITLIB ================================= // 2 | // Project: The Bit Library 3 | // License: BSD 3-Clause License 4 | // ========================================================================== // 5 | #ifndef _BITLIB_HPP_INCLUDED 6 | #define _BITLIB_HPP_INCLUDED 7 | 8 | #include "bit-iterator/bit.hpp" 9 | #include "bit-algorithms/bit_algorithm.hpp" 10 | #include "bit-containers/bit-containers.hpp" 11 | 12 | /*! \namespace bit 13 | * \brief All of the classes and functions of the BitLib 14 | */ 15 | 16 | #endif // _BITLIB_HPP_INCLUDED 17 | // ========================================================================== // 18 | -------------------------------------------------------------------------------- /profile/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set output directory of builds 2 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 3 | 4 | # set build type 5 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 6 | 7 | # Add targets 8 | file(GLOB PROFILE_SOURCES "src/*.cpp") 9 | add_executable(bitlib-profile ${PROFILE_SOURCES}) 10 | 11 | # specify benchmark-specific libraries 12 | include_directories(src/utils) 13 | 14 | target_compile_options(bitlib-profile PUBLIC -O2 -ggdb -Wpedantic) 15 | install(TARGETS bitlib-profile DESTINATION .) 16 | -------------------------------------------------------------------------------- /profile/src/main.cpp: -------------------------------------------------------------------------------- 1 | // ================================ PROFILE ================================= // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Used for profiling specific functions/algorithms 4 | // Creator: Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | 10 | // ============================== PREAMBLE ================================== // 11 | // C++ standard library 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | // Project sources 18 | #include "bitlib/bitlib.hpp" 19 | #include "test_utils.hpp" 20 | // Third party libraries 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | // ========================================================================== // 29 | 30 | 31 | 32 | int main() 33 | { 34 | using container_type = std::vector; 35 | const int container_size = 1 << 24; 36 | container_type bitcont = make_random_container(container_size); 37 | auto first = bit::bit_iterator(std::begin(bitcont)); 38 | auto last = bit::bit_iterator(std::end(bitcont)); 39 | auto n = 1 << 10; 40 | for (int i = 0; i < 100; i++) 41 | { 42 | if (i % 10 == 0) 43 | std::cerr << i << "\n"; 44 | bit::shift_left(first + 2, last, n + 4); 45 | } 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | ########### 3 | # Testing # 4 | ########### 5 | 6 | find_package(GTest REQUIRED) 7 | include(GoogleTest) 8 | 9 | file(GLOB TEST_SOURCES "src/*.cpp") 10 | add_executable(bitlib-tests ${TEST_SOURCES}) 11 | 12 | target_compile_options(bitlib-tests PUBLIC -O0 -g -fno-omit-frame-pointer -Wpedantic -fno-inline) 13 | 14 | if (BITLIB_COVERAGE) 15 | target_compile_options(bitlib-tests PUBLIC --coverage -fprofile-arcs -ftest-coverage -pg) 16 | endif() 17 | 18 | # ASAN throws no matter what when using Google HWY, not sure why but need to fix 19 | if (NOT BITLIB_HWY) 20 | target_compile_options(bitlib-tests PUBLIC -fsanitize=address) 21 | target_link_options(bitlib-tests PUBLIC -fsanitize=address) 22 | endif() 23 | 24 | # specify test-specific libraries 25 | include_directories(${googletest_SOURCE_DIR}/googletest/include/gtest src/utils) 26 | target_link_libraries(bitlib-tests PUBLIC GTest::gtest GTest::gtest_main -pthread -lgcov --coverage) 27 | 28 | if (NOT BITLIB_GTEST_REPEAT) 29 | set(BITLIB_GTEST_REPEAT 1) 30 | endif() 31 | 32 | enable_testing() 33 | gtest_discover_tests( 34 | bitlib-tests 35 | EXTRA_ARGS --gtest_repeat=${BITLIB_GTEST_REPEAT}) 36 | 37 | #add_test(bitlib-check 38 | #COMMAND env CTEST_OUTPUT_ON_FAILURE=1 GTEST_COLOR=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/bitlib-tests 39 | #DEPENDS bitlib-tests) 40 | -------------------------------------------------------------------------------- /test/src/fixtures.hpp: -------------------------------------------------------------------------------- 1 | // =============================== FIXTURES ================================= // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Fixtures for testing 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | #ifndef _FIXTURES_HPP_INCLUDED 8 | #define _FIXTURES_HPP_INCLUDED 9 | // ========================================================================== // 10 | 11 | 12 | // ============================== PREAMBLE ================================== // 13 | // C++ standard library 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | // Project sources 23 | #include "bitlib/bit-iterator/bit_iterator.hpp" 24 | #include "bitlib/bit-containers/bit-containers.hpp" 25 | #include "test_utils.hpp" 26 | // Third-party libraries 27 | #include "gtest/gtest.h" 28 | // Miscellaneous 29 | // ========================================================================== // 30 | 31 | 32 | //TODO tests need a lot of cleanup. We should only copy what we need from random_vec 33 | //and also refactor the vec generation to reduce duplication 34 | 35 | using BaseTypes = ::testing::Types; 36 | 37 | 38 | template 39 | class VectorTest : public testing::Test { 40 | protected: 41 | 42 | using base_type = WordType; 43 | using vec_type = bit::bit_vector; 44 | vec_type empty_vec; 45 | std::vector empty_vec_bool; 46 | vec_type v2_ = vec_type(18); 47 | vec_type v3_ = vec_type("010111111"); 48 | 49 | std::vector random_bitvecs; 50 | std::vector> random_boolvecs; 51 | std::vector random_vec; 52 | const size_t word_size = 4; 53 | const size_t digits = bit::binary_digits::value; 54 | const size_t bit_size = word_size*digits; 55 | 56 | void SetUp() override { 57 | empty_vec = vec_type(); 58 | random_vec = get_random_vec(word_size); 59 | for (size_t cont_size = 1; cont_size < bit_size; ++cont_size) { 60 | auto bitvec = vec_type(bit_size); 61 | std::memcpy(&(*bitvec.begin().base()), &(random_vec[0]), word_size); 62 | bitvec.resize(cont_size); 63 | 64 | auto boolvec = boolvec_from_bitvec(bitvec); 65 | random_bitvecs.push_back(bitvec); 66 | random_boolvecs.push_back(boolvec); 67 | } 68 | size_t big_size = 64*64*10; 69 | for (int i = -4; i < 4; ++i) { 70 | size_t cont_size = big_size + i; 71 | auto bitvec = vec_type(bit_size); 72 | std::memcpy(&(*bitvec.begin().base()), &(random_vec[0]), word_size); 73 | bitvec.resize(cont_size); 74 | 75 | auto boolvec = boolvec_from_bitvec(bitvec); 76 | random_bitvecs.push_back(bitvec); 77 | random_boolvecs.push_back(boolvec); 78 | } 79 | } 80 | }; 81 | TYPED_TEST_SUITE(VectorTest, BaseTypes); 82 | 83 | template 84 | class SingleRangeTest : public testing::Test { 85 | protected: 86 | 87 | using base_type = WordType; 88 | 89 | std::vector> random_bitvecs; 90 | std::vector> random_boolvecs; 91 | std::vector random_vec; 92 | size_t word_size = 4; 93 | size_t digits = bit::binary_digits::value; 94 | size_t bit_size = word_size*digits; 95 | 96 | void SetUp() override { 97 | random_vec = get_random_vec(word_size); 98 | for (size_t cont_size = 1; cont_size < bit_size; ++cont_size) { 99 | auto bitvec = bit::bit_vector(bit_size); 100 | std::copy(random_vec.begin(), random_vec.end(), bitvec.begin().base()); 101 | bitvec.resize(cont_size); 102 | 103 | auto boolvec = boolvec_from_bitvec(bitvec); 104 | random_bitvecs.push_back(bitvec); 105 | random_boolvecs.push_back(boolvec); 106 | } 107 | word_size = 2*64*64; 108 | random_vec = get_random_vec(word_size); 109 | size_t bit_size = (word_size)*digits; 110 | for (size_t cont_size = bit_size - digits - 4; cont_size < bit_size - digits + 4; ++cont_size) { 111 | auto bitvec = bit::bit_vector(bit_size); 112 | std::copy(random_vec.begin(), random_vec.end(), bitvec.begin().base()); 113 | bitvec.resize(cont_size); 114 | 115 | auto boolvec = boolvec_from_bitvec(bitvec); 116 | random_bitvecs.push_back(bitvec); 117 | random_boolvecs.push_back(boolvec); 118 | } 119 | 120 | auto zeros = bit::bit_vector(bit_size); 121 | std::fill(zeros.begin(), zeros.end(), bit::bit0); 122 | *(zeros.end() - 1024 - digits - 4) = bit::bit1; 123 | random_bitvecs.push_back(zeros); 124 | random_boolvecs.push_back(boolvec_from_bitvec(zeros)); 125 | 126 | auto ones = bit::bit_vector(bit_size); 127 | std::fill(ones.begin(), ones.end(), bit::bit1); 128 | *(ones.end() - 1024 - digits - 4) = bit::bit0; 129 | random_bitvecs.push_back(ones); 130 | random_boolvecs.push_back(boolvec_from_bitvec(ones)); 131 | } 132 | }; 133 | TYPED_TEST_SUITE(SingleRangeTest, BaseTypes); 134 | 135 | template 136 | class DoubleRangeTest : public testing::Test { 137 | protected: 138 | 139 | using base_type = WordType; 140 | 141 | std::vector> random_bitvecs1; 142 | std::vector> random_bitvecs2; 143 | std::vector> random_boolvecs1; 144 | std::vector> random_boolvecs2; 145 | std::vector random_vec; 146 | std::vector random_vec_big; 147 | size_t digits = bit::binary_digits::value; 148 | size_t word_size = 4; 149 | size_t bit_size = word_size*bit::binary_digits::value; 150 | size_t big_size = 64*64*2; 151 | 152 | void SetUp() override { 153 | // TODO this is ugly, need to refactor 154 | random_vec = get_random_vec(word_size); 155 | random_vec_big = get_random_vec(big_size); 156 | for (size_t cont_size = 1; cont_size < bit_size; ++cont_size) { 157 | auto bitvec = bit::bit_vector(bit_size); 158 | std::copy(random_vec.begin(), random_vec.end(), bitvec.begin().base()); 159 | bitvec.resize(cont_size); 160 | 161 | auto boolvec = boolvec_from_bitvec(bitvec); 162 | random_bitvecs1.push_back(bitvec); 163 | random_boolvecs1.push_back(boolvec); 164 | } 165 | for (int i = -4; i < 4; ++i) { 166 | size_t cont_size = (big_size-1)*digits + i; 167 | auto bitvec = bit::bit_vector(big_size*digits); 168 | std::copy(random_vec_big.begin(), random_vec_big.end(), bitvec.begin().base()); 169 | bitvec.resize(cont_size); 170 | 171 | auto boolvec = boolvec_from_bitvec(bitvec); 172 | random_bitvecs1.push_back(bitvec); 173 | random_boolvecs1.push_back(boolvec); 174 | } 175 | random_vec = get_random_vec(word_size); 176 | random_vec_big = get_random_vec(big_size); 177 | for (size_t cont_size = 1; cont_size < bit_size; ++cont_size) { 178 | auto bitvec = bit::bit_vector(bit_size); 179 | std::copy(random_vec.begin(), random_vec.end(), bitvec.begin().base()); 180 | bitvec.resize(cont_size); 181 | 182 | auto boolvec = boolvec_from_bitvec(bitvec); 183 | random_bitvecs2.push_back(bitvec); 184 | random_boolvecs2.push_back(boolvec); 185 | } 186 | for (int i = -4; i < 4; ++i) { 187 | size_t cont_size = (big_size-1)*digits + i; 188 | auto bitvec = bit::bit_vector(big_size*digits); 189 | std::copy(random_vec_big.begin(), random_vec_big.end(), bitvec.begin().base()); 190 | bitvec.resize(cont_size); 191 | 192 | auto boolvec = boolvec_from_bitvec(bitvec); 193 | random_bitvecs2.push_back(bitvec); 194 | random_boolvecs2.push_back(boolvec); 195 | } 196 | } 197 | }; 198 | TYPED_TEST_SUITE(DoubleRangeTest, BaseTypes); 199 | // ========================================================================== // 200 | #endif // _FIXTURES_HPP_INCLUDED 201 | // ========================================================================== // 202 | -------------------------------------------------------------------------------- /test/src/test-copy.cpp: -------------------------------------------------------------------------------- 1 | // ============================= COPY TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for copy algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(DoubleRangeTest, Copy) { 23 | for (size_t idx = 0; idx < this->random_bitvecs1.size(); ++idx) { 24 | using WordType = typename TestFixture::base_type; 25 | bit::bit_vector& bitvec1 = this->random_bitvecs1[idx]; 26 | bit::bit_vector& bitvec2 = this->random_bitvecs2[idx]; 27 | constexpr auto digits = bit::binary_digits::value; 28 | std::vector& boolvec1 = this->random_boolvecs1[idx]; 29 | std::vector& boolvec2 = this->random_boolvecs2[idx]; 30 | long long start1 = generate_random_number( 31 | 0, 32 | std::min(bitvec1.size() - 1, digits + 1)); 33 | long long start2 = generate_random_number( 34 | 0, 35 | std::min(bitvec2.size() - 1, digits + 1)); 36 | const auto min_range = (start2 > start1) ? start2 - start1 : 0; 37 | const auto max_range = std::max( 38 | min_range, 39 | std::min(digits, bitvec1.size() - start1)); 40 | long long end1 = generate_random_number(min_range, max_range); 41 | 42 | auto bitret = bit::copy( 43 | bitvec1.begin() + start1, 44 | bitvec1.end() - end1, 45 | bitvec2.begin() + start2); 46 | auto boolret = std::copy( 47 | boolvec1.begin() + start1, 48 | boolvec1.end() - end1, 49 | boolvec2.begin() + start2); 50 | EXPECT_EQ( 51 | bit::distance(bitvec2.begin(), bitret), 52 | std::distance(boolvec2.begin(), boolret)); 53 | EXPECT_TRUE(std::equal( 54 | bitvec2.begin(), bitvec2.end(), 55 | boolvec2.begin(), boolvec2.end(), comparator) 56 | ); 57 | start2 = generate_random_number(0, start1); 58 | bitret = bit::copy( 59 | bitvec1.begin() + start1, 60 | bitvec1.end() - end1, 61 | bitvec1.begin() + start2); 62 | boolret = std::copy( 63 | boolvec1.begin() + start1, 64 | boolvec1.end() - end1, 65 | boolvec1.begin() + start2); 66 | EXPECT_EQ( 67 | bit::distance(bitvec1.begin(), bitret), 68 | std::distance(boolvec1.begin(), boolret)); 69 | EXPECT_TRUE(std::equal( 70 | bitvec1.begin(), bitvec1.end(), 71 | boolvec1.begin(), boolvec1.end(), comparator) 72 | ); 73 | } 74 | } 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/src/test-copy_backward.cpp: -------------------------------------------------------------------------------- 1 | // ============================= COPY_BACKWARD TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for copy_backward algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(DoubleRangeTest, CopyBackward) { 23 | for (size_t idx = 0; idx < this->random_bitvecs1.size(); ++idx) { 24 | using WordType = typename TestFixture::base_type; 25 | bit::bit_vector& bitvec1 = this->random_bitvecs1[idx]; 26 | bit::bit_vector& bitvec2 = this->random_bitvecs2[idx]; 27 | constexpr auto digits = bit::binary_digits::value; 28 | std::vector& boolvec1 = this->random_boolvecs1[idx]; 29 | std::vector& boolvec2 = this->random_boolvecs2[idx]; 30 | long long start1 = generate_random_number( 31 | 0, 32 | std::min(bitvec1.size() - 1, digits + 1)); 33 | long long start2 = generate_random_number( 34 | 0, 35 | std::min(bitvec2.size() - 1, digits + 1)); 36 | const auto min_range = (start2 > start1) ? start2 - start1 : 0; 37 | const auto max_range = std::max( 38 | min_range, 39 | std::min(digits, bitvec1.size() - start1)); 40 | long long end1 = generate_random_number(min_range, max_range); 41 | auto d = (bitvec1.size() - end1) - start1; 42 | 43 | auto bitret = bit::copy_backward( 44 | bitvec1.begin() + start1, 45 | bitvec1.end() - end1, 46 | bitvec2.begin() + start2 + d); 47 | auto boolret = std::copy_backward( 48 | boolvec1.begin() + start1, 49 | boolvec1.end() - end1, 50 | boolvec2.begin() + start2 + d); 51 | EXPECT_EQ( 52 | bit::distance(bitvec2.begin(), bitret), 53 | std::distance(boolvec2.begin(), boolret)); 54 | EXPECT_TRUE(std::equal( 55 | bitvec2.begin(), bitvec2.end(), 56 | boolvec2.begin(), boolvec2.end(), comparator) 57 | ); 58 | start2 = generate_random_number(start1, start1 + end1); 59 | bitret = bit::copy_backward( 60 | bitvec1.begin() + start1, 61 | bitvec1.end() - end1, 62 | bitvec1.begin() + start2 + d); 63 | boolret = std::copy_backward( 64 | boolvec1.begin() + start1, 65 | boolvec1.end() - end1, 66 | boolvec1.begin() + start2 + d); 67 | EXPECT_EQ( 68 | bit::distance(bitvec1.begin(), bitret), 69 | std::distance(boolvec1.begin(), boolret)); 70 | EXPECT_TRUE(std::equal( 71 | bitvec1.begin(), bitvec1.end(), 72 | boolvec1.begin(), boolvec1.end(), comparator) 73 | ); 74 | } 75 | } 76 | 77 | 78 | -------------------------------------------------------------------------------- /test/src/test-count.cpp: -------------------------------------------------------------------------------- 1 | // ============================== COUNT TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for count algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(SingleRangeTest, Count) { 23 | for (size_t idx = 0; idx < this->bit_size - 1; ++idx) { 24 | bit::bit_vector bitvec = this->random_bitvecs[idx]; 25 | std::vector boolvec = this->random_boolvecs[idx]; 26 | size_t start_count = 16; 27 | while (start_count--) { 28 | unsigned long long start = generate_random_number(0, std::min(bitvec.size() - 1, 16)); 29 | auto bitret = bit::count(bitvec.begin() + start, bitvec.end(), bit::bit1); 30 | auto boolret = std::count(boolvec.begin() + start, boolvec.end(), true); 31 | EXPECT_EQ(bitret, boolret); 32 | bitret = bit::count(bitvec.begin() + start, bitvec.end(), bit::bit0); 33 | boolret = std::count(boolvec.begin() + start, boolvec.end(), false); 34 | EXPECT_EQ(bitret, boolret); 35 | } 36 | } 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/src/test-equal.cpp: -------------------------------------------------------------------------------- 1 | // ============================= EQUAL TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for equal algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(DoubleRangeTest, Equal) { 23 | for (size_t idx = 0; idx < this->random_bitvecs1.size(); ++idx) { 24 | using WordType = typename TestFixture::base_type; 25 | bit::bit_vector& bitvec1 = this->random_bitvecs1[idx]; 26 | bit::bit_vector& bitvec2 = this->random_bitvecs2[idx]; 27 | constexpr auto digits = bit::binary_digits::value; 28 | std::vector& boolvec1 = this->random_boolvecs1[idx]; 29 | std::vector& boolvec2 = this->random_boolvecs2[idx]; 30 | long long start1 = generate_random_number( 31 | 0, 32 | std::min(bitvec1.size() - 1, digits + 1)); 33 | long long start2 = generate_random_number( 34 | 0, 35 | std::min(bitvec2.size() - 1, digits + 1)); 36 | const auto min_range = (start2 > start1) ? start2 - start1 : 0; 37 | const auto max_range = std::max( 38 | min_range, 39 | std::min(digits, bitvec1.size() - start1)); 40 | long long end1 = generate_random_number(min_range, max_range); 41 | 42 | auto bitret = bit::equal( 43 | bitvec1.begin() + start1, 44 | bitvec1.end() - end1, 45 | bitvec2.begin() + start2); 46 | auto boolret = std::equal( 47 | boolvec1.begin() + start1, 48 | boolvec1.end() - end1, 49 | boolvec2.begin() + start2); 50 | EXPECT_EQ(boolret, bitret); 51 | EXPECT_TRUE(std::equal( 52 | bitvec2.begin(), bitvec2.end(), 53 | boolvec2.begin(), boolvec2.end(), comparator) 54 | ); 55 | bit::copy( 56 | bitvec1.begin() + start1, 57 | bitvec1.end() - end1, 58 | bitvec2.begin() + start2); 59 | std::copy( 60 | boolvec1.begin() + start1, 61 | boolvec1.end() - end1, 62 | boolvec2.begin() + start2); 63 | bitret = bit::equal( 64 | bitvec1.begin() + start1, 65 | bitvec1.end() - end1, 66 | bitvec2.begin() + start2); 67 | boolret = std::equal( 68 | boolvec1.begin() + start1, 69 | boolvec1.end() - end1, 70 | boolvec2.begin() + start2); 71 | EXPECT_EQ(boolret, bitret); 72 | EXPECT_TRUE(std::equal( 73 | bitvec1.begin(), bitvec1.end(), 74 | boolvec1.begin(), boolvec1.end(), comparator) 75 | ); 76 | } 77 | } 78 | 79 | 80 | -------------------------------------------------------------------------------- /test/src/test-fill.cpp: -------------------------------------------------------------------------------- 1 | // ============================= FILL TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for fill algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(SingleRangeTest, Fill) { 23 | for (size_t idx = 0; idx < this->random_bitvecs.size(); ++idx) { 24 | using WordType = typename TestFixture::base_type; 25 | bit::bit_vector& bitvec = this->random_bitvecs[idx]; 26 | std::vector& boolvec = this->random_boolvecs[idx]; 27 | ASSERT_EQ(boolvec.size(), bitvec.size()); 28 | constexpr auto digits = bit::binary_digits::value; 29 | unsigned long long start = generate_random_number( 30 | 0, 31 | std::min(bitvec.size(), digits + 1)); 32 | unsigned long long end = generate_random_number( 33 | 0, 34 | std::min(digits + 1, bitvec.size() - start)); 35 | auto fill_val_bit = bit::bit1; 36 | auto fill_val_bool = true; 37 | bit::fill(bitvec.begin() + start, bitvec.end() - end, fill_val_bit); 38 | std::fill(boolvec.begin() + start, boolvec.end() - end, fill_val_bool); 39 | EXPECT_TRUE(std::equal( 40 | bitvec.begin(), bitvec.end(), 41 | boolvec.begin(), boolvec.end(), comparator) 42 | ); 43 | start = generate_random_number( 44 | 0, 45 | std::min(bitvec.size(), digits + 1)); 46 | end = generate_random_number( 47 | 0, 48 | std::min(digits + 1, bitvec.size() - start)); 49 | fill_val_bit = bit::bit0; 50 | fill_val_bool = false; 51 | bit::fill(bitvec.begin() + start, bitvec.end() - end, fill_val_bit); 52 | std::fill(boolvec.begin() + start, boolvec.end() - end, fill_val_bool); 53 | EXPECT_TRUE(std::equal( 54 | bitvec.begin(), bitvec.end(), 55 | boolvec.begin(), boolvec.end(), comparator) 56 | ); 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /test/src/test-find.cpp: -------------------------------------------------------------------------------- 1 | // ============================== FIND TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for find algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(SingleRangeTest, Find) { 23 | for (size_t idx = 0; idx < this->random_bitvecs.size(); ++idx) { 24 | bit::bit_vector bitvec = this->random_bitvecs[idx]; 25 | std::vector boolvec = this->random_boolvecs[idx]; 26 | size_t start_count = 16; 27 | while (start_count--) { 28 | unsigned long long start = generate_random_number(0, std::min(bitvec.size() - 1, 16)); 29 | auto bitret = bit::find(bitvec.begin() + start, bitvec.end(), bit::bit1); 30 | auto boolret = std::find(boolvec.begin() + start, boolvec.end(), true); 31 | EXPECT_EQ(std::distance(bitvec.begin(), bitret), std::distance(boolvec.begin(), boolret)); 32 | bitret = bit::find(bitvec.begin() + start, bitvec.end(), bit::bit0); 33 | boolret = std::find(boolvec.begin() + start, boolvec.end(), false); 34 | EXPECT_EQ(std::distance(bitvec.begin(), bitret), std::distance(boolvec.begin(), boolret)); 35 | } 36 | } 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/src/test-move.cpp: -------------------------------------------------------------------------------- 1 | // ============================= MOVE TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for move algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(DoubleRangeTest, Move) { 23 | for (size_t idx = 0; idx < this->random_bitvecs1.size(); ++idx) { 24 | using WordType = typename TestFixture::base_type; 25 | bit::bit_vector& bitvec1 = this->random_bitvecs1[idx]; 26 | bit::bit_vector& bitvec2 = this->random_bitvecs2[idx]; 27 | constexpr auto digits = bit::binary_digits::value; 28 | std::vector& boolvec1 = this->random_boolvecs1[idx]; 29 | std::vector& boolvec2 = this->random_boolvecs2[idx]; 30 | long long start1 = generate_random_number( 31 | 0, 32 | std::min(bitvec1.size() - 1, digits + 1)); 33 | long long start2 = generate_random_number( 34 | 0, 35 | std::min(bitvec2.size() - 1, digits + 1)); 36 | const auto min_range = (start2 > start1) ? start2 - start1 : 0; 37 | const auto max_range = std::max( 38 | min_range, 39 | std::min(digits, bitvec1.size() - start1)); 40 | long long end1 = generate_random_number(min_range, max_range); 41 | 42 | auto bitret = bit::move( 43 | bitvec1.begin() + start1, 44 | bitvec1.end() - end1, 45 | bitvec2.begin() + start2); 46 | auto boolret = std::move( 47 | boolvec1.begin() + start1, 48 | boolvec1.end() - end1, 49 | boolvec2.begin() + start2); 50 | EXPECT_EQ( 51 | bit::distance(bitvec2.begin(), bitret), 52 | std::distance(boolvec2.begin(), boolret)); 53 | EXPECT_TRUE(std::equal( 54 | bitvec2.begin(), bitvec2.end(), 55 | boolvec2.begin(), boolvec2.end(), comparator) 56 | ); 57 | start2 = generate_random_number(0, start1); 58 | bitret = bit::move( 59 | bitvec1.begin() + start1, 60 | bitvec1.end() - end1, 61 | bitvec1.begin() + start2); 62 | boolret = std::move( 63 | boolvec1.begin() + start1, 64 | boolvec1.end() - end1, 65 | boolvec1.begin() + start2); 66 | EXPECT_EQ( 67 | bit::distance(bitvec1.begin(), bitret), 68 | std::distance(boolvec1.begin(), boolret)); 69 | EXPECT_TRUE(std::equal( 70 | bitvec1.begin(), bitvec1.end(), 71 | boolvec1.begin(), boolvec1.end(), comparator) 72 | ); 73 | } 74 | } 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/src/test-reverse.cpp: -------------------------------------------------------------------------------- 1 | // ============================= REVERSE TESTS ============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for count algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(SingleRangeTest, Reverse) { 23 | for (size_t idx = 0; idx < this->random_bitvecs.size(); ++idx) { 24 | bit::bit_vector bitvec = this->random_bitvecs[idx]; 25 | std::vector boolvec = this->random_boolvecs[idx]; 26 | size_t start_count = 16; 27 | while (start_count--) { 28 | unsigned long long start = generate_random_number(0, std::min(bitvec.size() - 1, 16)); 29 | bit::reverse(bitvec.begin() + start, bitvec.end()); 30 | std::reverse(boolvec.begin() + start, boolvec.end()); 31 | EXPECT_TRUE(std::equal( 32 | bitvec.begin(), bitvec.end(), 33 | boolvec.begin(), boolvec.end(), comparator) 34 | ); 35 | } 36 | } 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/src/test-rotate.cpp: -------------------------------------------------------------------------------- 1 | // ============================= ROTATE TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: rotate.hpp 4 | // Description: Tests for rotate algorithms 5 | // Contributor(s): Bryce Kille 6 | // License: BSD 3-Clause License 7 | // ========================================================================== // 8 | 9 | 10 | // ============================== PREAMBLE ================================== // 11 | // C++ standard library 12 | #include 13 | #include 14 | // Project sources 15 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 16 | #include "bitlib/bit-containers/bit-containers.hpp" 17 | #include "fixtures.hpp" 18 | // Third-party libraries 19 | #include "gtest/gtest.h" 20 | // Miscellaneous 21 | // ========================================================================== // 22 | 23 | TYPED_TEST(SingleRangeTest, Rotate) { 24 | using WordType = typename TestFixture::base_type; 25 | for (size_t idx = 0; idx < this->random_bitvecs.size(); ++idx) { 26 | bit::bit_vector& bitvec = this->random_bitvecs[idx]; 27 | std::vector boolvec = this->random_boolvecs[idx]; 28 | size_t start_count = 4; 29 | while (start_count--) { 30 | unsigned long long start = generate_random_number(0, std::min(bitvec.size() - 1, 16)); 31 | size_t middle_count = 4; 32 | while (middle_count--) { 33 | unsigned long long middle = generate_random_number(start, bitvec.size() - 1); 34 | auto bitret = bit::rotate(bitvec.begin() + start, bitvec.begin() + middle, bitvec.end()); 35 | auto boolret = std::rotate(boolvec.begin() + start, boolvec.begin() + middle, boolvec.end()); 36 | EXPECT_TRUE(std::equal( 37 | bitvec.begin(), bitvec.end(), 38 | boolvec.begin(), boolvec.end(), comparator) 39 | ); 40 | EXPECT_EQ(std::distance(bitvec.begin(), bitret), std::distance(boolvec.begin(), boolret)); 41 | } 42 | } 43 | } 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /test/src/test-shift.cpp: -------------------------------------------------------------------------------- 1 | // ============================= SHIFT TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for shift algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(SingleRangeTest, ShiftLeft) { 23 | for (size_t idx = 0; idx < this->random_bitvecs.size(); ++idx) { 24 | using WordType = typename TestFixture::base_type; 25 | bit::bit_vector& bitvec = this->random_bitvecs[idx]; 26 | std::vector& boolvec = this->random_boolvecs[idx]; 27 | ASSERT_EQ(boolvec.size(), bitvec.size()); 28 | constexpr auto digits = bit::binary_digits::value; 29 | unsigned long long start = generate_random_number( 30 | 0, 31 | std::min(bitvec.size(), digits + 1)); 32 | unsigned long long shift_val = generate_random_number(0, bitvec.size() + 1); 33 | auto bitret = bit::shift_left(bitvec.begin() + start, bitvec.end(), shift_val); 34 | auto boolret = bit::word_shift_left(boolvec.begin() + start, boolvec.end(), shift_val); 35 | EXPECT_EQ(std::distance(bitvec.begin(), bitret), std::distance(boolvec.begin(), boolret)); 36 | EXPECT_TRUE(std::equal( 37 | bitvec.begin(), bitret, 38 | boolvec.begin(), boolret, comparator) 39 | ); 40 | } 41 | } 42 | 43 | 44 | TYPED_TEST(SingleRangeTest, ShiftRight) { 45 | for (size_t idx = 0; idx < this->random_bitvecs.size(); ++idx) { 46 | using WordType = typename TestFixture::base_type; 47 | bit::bit_vector& bitvec = this->random_bitvecs[idx]; 48 | std::vector& boolvec = this->random_boolvecs[idx]; 49 | ASSERT_EQ(boolvec.size(), bitvec.size()); 50 | constexpr auto digits = bit::binary_digits::value; 51 | unsigned long long start = generate_random_number( 52 | 0, 53 | std::min(bitvec.size(), digits + 1)); 54 | unsigned long long shift_val = generate_random_number(0, bitvec.size() + 1); 55 | auto bitret = bit::shift_right(bitvec.begin() + start, bitvec.end(), shift_val); 56 | auto boolret = bit::word_shift_right(boolvec.begin() + start, boolvec.end(), shift_val); 57 | EXPECT_EQ(std::distance(bitvec.begin(), bitret), std::distance(boolvec.begin(), boolret)); 58 | EXPECT_TRUE(std::equal( 59 | bitret, bitvec.end(), 60 | boolret, boolvec.end(), comparator) 61 | ); 62 | } 63 | } 64 | 65 | //REGISTER_TYPED_TEST_SUITE_P(, DoesBlah, HasPropertyA); 66 | //INSTANTIATE_TYPED_TEST_SUITE_P(Instantiation, SingleRangeTest, BaseTypes); 67 | -------------------------------------------------------------------------------- /test/src/test-swap_ranges.cpp: -------------------------------------------------------------------------------- 1 | // ============================= SWAP_RANGES TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for swap_ranges algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | // Project sources 14 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 15 | #include "bitlib/bit-containers/bit-containers.hpp" 16 | #include "fixtures.hpp" 17 | // Third-party libraries 18 | #include "gtest/gtest.h" 19 | // Miscellaneous 20 | // ========================================================================== // 21 | 22 | TYPED_TEST(DoubleRangeTest, SwapRanges) { 23 | for (size_t idx = 0; idx < this->random_bitvecs1.size(); ++idx) { 24 | using WordType = typename TestFixture::base_type; 25 | bit::bit_vector& bitvec1 = this->random_bitvecs1[idx]; 26 | bit::bit_vector& bitvec2 = this->random_bitvecs2[idx]; 27 | constexpr auto digits = bit::binary_digits::value; 28 | std::vector& boolvec1 = this->random_boolvecs1[idx]; 29 | std::vector& boolvec2 = this->random_boolvecs2[idx]; 30 | long long start1 = generate_random_number( 31 | 0, 32 | std::min(bitvec1.size() - 1, digits + 1)); 33 | long long start2 = generate_random_number( 34 | 0, 35 | std::min(bitvec2.size() - 1, digits + 1)); 36 | const auto min_range = (start2 > start1) ? start2 - start1 : 0; 37 | const auto max_range = std::max( 38 | min_range, 39 | std::min(digits, bitvec1.size() - start1)); 40 | long long end1 = generate_random_number(min_range, max_range); 41 | 42 | auto bitret = bit::swap_ranges( 43 | bitvec1.begin() + start1, 44 | bitvec1.end() - end1, 45 | bitvec2.begin() + start2); 46 | auto boolret = std::swap_ranges( 47 | boolvec1.begin() + start1, 48 | boolvec1.end() - end1, 49 | boolvec2.begin() + start2); 50 | EXPECT_EQ( 51 | bit::distance(bitvec2.begin(), bitret), 52 | std::distance(boolvec2.begin(), boolret)); 53 | EXPECT_TRUE(std::equal( 54 | bitvec2.begin(), bitvec2.end(), 55 | boolvec2.begin(), boolvec2.end(), comparator) 56 | ); 57 | } 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /test/src/test-transform.cpp: -------------------------------------------------------------------------------- 1 | // ============================= TRANSFORM TESTS =============================== // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Description: Tests for transform algorithms 4 | // Contributor(s): Bryce Kille 5 | // License: BSD 3-Clause License 6 | // ========================================================================== // 7 | 8 | 9 | // ============================== PREAMBLE ================================== // 10 | // C++ standard library 11 | #include 12 | #include 13 | #include 14 | // Project sources 15 | #include "bitlib/bit-algorithms/bit_algorithm.hpp" 16 | #include "bitlib/bit-containers/bit-containers.hpp" 17 | #include "fixtures.hpp" 18 | // Third-party libraries 19 | #include "gtest/gtest.h" 20 | // Miscellaneous 21 | // ========================================================================== // 22 | 23 | TYPED_TEST(DoubleRangeTest, TransformUnaryOp) { 24 | for (size_t idx = 0; idx < this->random_bitvecs1.size() - 1; ++idx) { 25 | using WordType = typename TestFixture::base_type; 26 | bit::bit_vector& bitvec1 = this->random_bitvecs1[idx]; 27 | bit::bit_vector& bitvec2 = this->random_bitvecs2[idx]; 28 | constexpr auto digits = bit::binary_digits::value; 29 | std::vector& boolvec1 = this->random_boolvecs1[idx]; 30 | std::vector& boolvec2 = this->random_boolvecs2[idx]; 31 | long long start1 = generate_random_number( 32 | 0, 33 | std::min(bitvec1.size() - 1, digits + 1)); 34 | long long start2 = generate_random_number( 35 | 0, 36 | std::min(bitvec2.size() - 1, digits + 1)); 37 | const auto min_range = (start2 > start1) ? start2 - start1 : 0; 38 | const auto max_range = std::max( 39 | min_range, 40 | std::min(digits, bitvec1.size() - start1)); 41 | long long end1 = generate_random_number(min_range, max_range); 42 | 43 | auto unary_op_bit = std::bit_not(); 44 | auto unary_op_bool = [](bool b) {return !b;}; 45 | auto bitret = bit::transform( 46 | bitvec1.begin() + start1, 47 | bitvec1.end() - end1, 48 | bitvec2.begin() + start2, 49 | unary_op_bit); 50 | auto boolret = std::transform( 51 | boolvec1.begin() + start1, 52 | boolvec1.end() - end1, 53 | boolvec2.begin() + start2, 54 | unary_op_bool); 55 | EXPECT_EQ( 56 | bit::distance(bitvec2.begin(), bitret), 57 | std::distance(boolvec2.begin(), boolret)); 58 | EXPECT_TRUE(std::equal( 59 | bitvec2.begin(), bitvec2.end(), 60 | boolvec2.begin(), boolvec2.end(), comparator) 61 | ); 62 | } 63 | } 64 | 65 | TYPED_TEST(DoubleRangeTest, TransformBinaryOp) { 66 | for (size_t idx = 0; idx < this->random_bitvecs1.size() - 1; ++idx) { 67 | using WordType = typename TestFixture::base_type; 68 | bit::bit_vector& bitvec1 = this->random_bitvecs1[idx]; 69 | bit::bit_vector& bitvec2 = this->random_bitvecs2[idx]; 70 | constexpr auto digits = bit::binary_digits::value; 71 | std::vector& boolvec1 = this->random_boolvecs1[idx]; 72 | std::vector& boolvec2 = this->random_boolvecs2[idx]; 73 | long long start1 = generate_random_number( 74 | 0, 75 | std::min(bitvec1.size() - 1, digits + 1)); 76 | long long start2 = generate_random_number( 77 | 0, 78 | std::min(bitvec2.size() - 1, digits + 1)); 79 | const auto min_range = (start2 > start1) ? start2 - start1 : 0; 80 | const auto max_range = std::max( 81 | min_range, 82 | std::min(digits, bitvec1.size() - start1)); 83 | long long end1 = generate_random_number(min_range, max_range); 84 | auto binary_op_bit = std::bit_and(); 85 | auto binary_op_bool = [](bool a, bool b) {return a && b;}; 86 | auto bitret = bit::transform( 87 | bitvec1.begin() + start1, 88 | bitvec1.end() - end1, 89 | bitvec2.begin() + start2, 90 | bitvec2.begin() + start2, 91 | binary_op_bit); 92 | auto boolret = std::transform( 93 | boolvec1.begin() + start1, 94 | boolvec1.end() - end1, 95 | boolvec2.begin() + start2, 96 | boolvec2.begin() + start2, 97 | binary_op_bool); 98 | EXPECT_EQ( 99 | bit::distance(bitvec2.begin(), bitret), 100 | std::distance(boolvec2.begin(), boolret)); 101 | EXPECT_TRUE(std::equal( 102 | bitvec2.begin(), bitvec2.end(), 103 | boolvec2.begin(), boolvec2.end(), comparator) 104 | ); 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /utils/test_utils.hpp: -------------------------------------------------------------------------------- 1 | // ============================= TEST_UTILS ================================ // 2 | // Project: The Experimental Bit Algorithms Library 3 | // Name: test_utils.hpp 4 | // Description: General utilities for testing 5 | // Creator: Bryce Kille 6 | // Contributor(s): Bryce Kille [2019], 7 | // Collin Gress [2019] 8 | // License: BSD 3-Clause License 9 | // ========================================================================== // 10 | #ifndef _TEST_UTILS_HPP_INCLUDED 11 | #define _TEST_UTILS_HPP_INCLUDED 12 | // ========================================================================== // 13 | 14 | 15 | // ================================ PREAMBLE ================================ // 16 | // C++ standard library 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | // Project sources 24 | #include "bitlib/bitlib.hpp" 25 | // Third-party libraries 26 | // Miscellaneous 27 | 28 | 29 | // =============================== DEBUGGING ================================ // 30 | 31 | // ================================ TESTING ================================- // 32 | 33 | // Comparator for bit_iterator to other iterators 34 | constexpr auto comparator = [](auto b1, auto b2){ 35 | return static_cast(b1) == static_cast(b2); 36 | }; 37 | 38 | // Helper struct for rebind_container 39 | template struct rebind_container; 40 | 41 | // Helper struct for rebind_container 42 | template class Container, 45 | class NewType, 46 | class... Parameters 47 | > 48 | struct rebind_container, NewType> 49 | { 50 | typedef Container::other > type; 51 | }; 52 | 53 | 54 | // Takes in Container and returns Container of the same underlying bits 55 | template 56 | auto bitcont_to_boolcont(const Container bitcont){ 57 | auto bfirst = bit::bit_iterator(std::begin(bitcont)); 58 | auto blast = bit::bit_iterator(std::end(bitcont)); 59 | typename rebind_container::type c(std::distance(bfirst, 60 | blast) 61 | ); 62 | auto benchmark_it = std::begin(c); 63 | auto it = bfirst; 64 | for (; it != blast; ++it, ++benchmark_it) { 65 | *benchmark_it = static_cast(*it); 66 | } 67 | return c; 68 | } 69 | 70 | // Produces container of random numbers from min to max 71 | template 72 | Container make_random_container( 73 | std::size_t size, 74 | T min = std::numeric_limits::min(), 75 | T max = std::numeric_limits::max(), 76 | const T& seed = T() 77 | ) 78 | { 79 | Container c(size); 80 | std::random_device device; 81 | std::mt19937 engine(seed == T() ? device() : seed); 82 | std::uniform_int_distribution distribution(min, max); 83 | auto it = std::begin(c); 84 | for (std::size_t i = 0; i < size; ++i) { 85 | *it = distribution(engine); 86 | ++it; 87 | } 88 | return c; 89 | } 90 | 91 | 92 | inline unsigned long long generate_random_number(size_t min, size_t max) { 93 | // First create an instance of an engine. 94 | std::random_device rnd_device; 95 | // Specify the engine and distribution. 96 | std::mt19937 mersenne_engine {rnd_device()}; // Generates random integers 97 | std::uniform_int_distribution dist {min, max}; 98 | 99 | return dist(mersenne_engine); 100 | } 101 | 102 | 103 | template 104 | std::vector get_random_vec( 105 | unsigned long long int size, 106 | WordType min = std::numeric_limits::min(), 107 | WordType max = std::numeric_limits::max() 108 | ) { 109 | // First create an instance of an engine. 110 | std::random_device rnd_device; 111 | // Specify the engine and distribution. 112 | std::mt19937 mersenne_engine {rnd_device()}; // Generates random integers 113 | std::uniform_int_distribution dist {min, max}; 114 | 115 | auto gen = [&dist, &mersenne_engine](){ 116 | return dist(mersenne_engine); 117 | }; 118 | std::vector vec(size); 119 | generate(begin(vec), end(vec), gen); 120 | return vec; 121 | } 122 | 123 | template 124 | bit::bit_vector get_random_bvec( 125 | unsigned long long int size 126 | ) { 127 | constexpr auto digits = bit::binary_digits::value; 128 | auto words = (size + digits - 1) / digits; 129 | auto word_vec = get_random_vec(words); 130 | bit::bit_vector ret(word_vec.begin(), word_vec.end()); 131 | ret.resize(size); 132 | return ret; 133 | } 134 | 135 | template 136 | std::vector boolvec_from_bitvec(bit::bit_vector bv) { 137 | std::vector ret_vec{}; 138 | for (bit::bit_value value : bv) { 139 | ret_vec.push_back(value == bit::bit1 ? true : false); 140 | } 141 | return ret_vec; 142 | } 143 | 144 | // ========================================================================== // 145 | #endif // _TEST_UTILS_HPP_INCLUDED 146 | // ========================================================================== // 147 | --------------------------------------------------------------------------------