├── .gitignore ├── .travis.yml ├── Cargo.toml ├── benches ├── gcd.rs └── morton.rs ├── build.rs ├── clippy.toml ├── examples └── readme.rs ├── license.md ├── readme.md └── src ├── lib.rs └── word ├── align_down.rs ├── align_up.rs ├── ceil_pow2.rs ├── clear_bit.rs ├── clear_bits_geq.rs ├── clear_bits_leq.rs ├── clear_least_significant_one.rs ├── clear_trailing_ones.rs ├── copy_bit.rs ├── count_leading_ones.rs ├── count_leading_zeros.rs ├── count_ones.rs ├── count_trailing_ones.rs ├── count_trailing_zeros.rs ├── count_zeros.rs ├── extract_bits.rs ├── flip_bit.rs ├── flip_bits_geq.rs ├── flip_bits_leq.rs ├── floor_pow2.rs ├── from_be.rs ├── from_le.rs ├── gcd.rs ├── greatest_common_divisor.rs ├── hamming_distance.rs ├── inner_perfect_shuffle.rs ├── inner_perfect_unshuffle.rs ├── is_aligned.rs ├── is_even.rs ├── is_odd.rs ├── is_pow2.rs ├── isolate_least_significant_one.rs ├── isolate_least_significant_zero.rs ├── mask_trailing_ones.rs ├── mask_trailing_ones_and_least_significant_zero.rs ├── mask_trailing_zeros.rs ├── mask_trailing_zeros_and_least_significant_one.rs ├── mod.rs ├── morton.rs ├── outer_perfect_shuffle.rs ├── outer_perfect_unshuffle.rs ├── parallel_bits_deposit.rs ├── parallel_bits_extract.rs ├── parity.rs ├── pow.rs ├── reverse_bit_groups.rs ├── reverse_bit_nibbles.rs ├── reverse_bit_pairs.rs ├── reverse_bits.rs ├── reverse_byte_groups.rs ├── reverse_bytes.rs ├── rotate_left.rs ├── rotate_right.rs ├── set_bit.rs ├── set_bits_geq.rs ├── set_bits_leq.rs ├── set_least_significant_zero.rs ├── set_trailing_zeros.rs ├── shift_arithmetic_left.rs ├── shift_arithmetic_right.rs ├── shift_logical_left.rs ├── shift_logical_right.rs ├── swap_bytes.rs ├── test_bit.rs ├── to_be.rs ├── to_le.rs ├── to_word.rs └── word.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 7 | Cargo.lock 8 | 9 | # Rustfmt backup files 10 | *.rs.bk 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | addons: 4 | apt: 5 | packages: 6 | - libcurl4-openssl-dev 7 | - libelf-dev 8 | - libdw-dev 9 | - binutils-dev 10 | rust: 11 | - nightly 12 | #- stable 13 | #- 1.13.0 14 | 15 | before_script: 16 | - ! 'pip install ''travis-cargo<0.2'' --user && 17 | 18 | export PATH=$HOME/.local/bin:$PATH 19 | 20 | ' 21 | script: 22 | - ! 'travis-cargo build && 23 | 24 | travis-cargo test && 25 | 26 | travis-cargo bench && 27 | 28 | travis-cargo --only nightly doc 29 | 30 | ' 31 | after_success: 32 | - travis-cargo --only nightly doc-upload 33 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then travis-cargo coveralls --no-sudo --verify; 34 | fi 35 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./kcov/build/src/kcov --verify --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo target/kcov target/debug/deps/bitwise-*; fi 36 | env: 37 | global: 38 | - TRAVIS_CARGO_NIGHTLY_FEATURE="" 39 | - secure: CBkbWUVQ1pvKRYqgbpqmNnvpOXgmlyNoeprMhIQjNIDfKh/CW0EPeso2IvbgfwJFGPWwcmmwdl1K8NXR0J9oIGY0VD449p4K4ZAHV9W0TMoTfth5LNrls7NNQxMEABl7U/3mAEFpK1SxwS/CWCtHhGrOnZlLsbabTERJkHYK+ui9RFb8NYhwxm5me3GSEdTc3JNQ/4DfNaBEIcus67xY3FQU0VphkTDxhDOHnGzgj4+fU9UWldvdkWru9in2D4mmT82FZSPOKBQpRTe5twaTxPDvAU4uFanIw3G1Hxl5/m9EYkMx1ppwOLswp4DZxzVdcJbk/k7ZKcz5FSZVckoRx3C6O8ItHe0prNRp2YUbVY2P+1TOyuKISq5P1cEtGQW+K4cNtBD/sg68HUzJpcemG/5CYJpsHK2yLPV0F/oJLpdP7kqlatYFCg/mpoO/sgjUD6ChhghMm/JR/Ifcfdfic8t8gLm9tRxL4axek2sNNXMi7GDlnM8rIfOCdr8SIFDu53hyovZb7MDzLleeV66CIKpMqluDFThkb4dvuzeGyIDXnJRd9bRaMCGSw2qPX+Iyhm4vnPhYfHmcV9/C0nlqrTJTuDnrNGvjv6umIHK92mTaasjwIpnCaJ6kGAZq/COgz/bHU8XB4/Z3DPe7pnq+9qR4GwdybgeCp2raKey/WZI= 40 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bitwise" 3 | version = "0.2.0" 4 | authors = ["gnzlbg "] 5 | description = "Portable high-level bitwise manipulation algorithms." 6 | documentation = "https://gnzlbg.github.io/bitwise" 7 | homepage = "https://gnzlbg.github.io/bitwise" 8 | repository = "https://github.com/gnzlbg/bitwise" 9 | readme = "readme.md" 10 | keywords = ["portable", "bit", "manipulation", "algorithms"] 11 | license = "MIT" 12 | build = "build.rs" 13 | categories = ["algorithms", "hardware-support", "no-std"] 14 | 15 | [badges] 16 | travis-ci = { repository = "gnzlbg/bitwise", branch = "master" } 17 | 18 | [build-dependencies] 19 | rustc_version = "0.2" 20 | 21 | [dependencies] 22 | bitintr = "0.2" 23 | 24 | [dev-dependencies] 25 | bencher = "0.1" 26 | quickcheck = "0.6" 27 | 28 | [[bench]] 29 | name = "morton" 30 | bench = true 31 | harness = false 32 | 33 | [[bench]] 34 | name = "gcd" 35 | bench = true 36 | harness = false 37 | 38 | 39 | [profile.bench] 40 | opt-level = 3 41 | debug = false 42 | rpath = false 43 | lto = true 44 | debug-assertions = false 45 | codegen-units = 1 46 | panic = 'abort' 47 | -------------------------------------------------------------------------------- /benches/gcd.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | #[macro_use] 4 | extern crate bencher; 5 | 6 | extern crate bitwise; 7 | 8 | use bencher::Bencher; 9 | 10 | use bitwise::word::gcd; 11 | 12 | 13 | 14 | pub fn run_u8_small u8>(b: &mut Bencher, f: F) { 15 | b.iter(|| gcd::test_util::run_u8(0, u8::max_value() / 3, 16 | |x, y| bencher::black_box(f(bencher::black_box(x), 17 | bencher::black_box(y))))); 18 | } 19 | 20 | pub fn run_u8_mid u8>(b: &mut Bencher, f: F) { 21 | b.iter(|| gcd::test_util::run_u8(u8::max_value() / 3, u8::max_value() / 3 * 2, 22 | |x, y| bencher::black_box(f(bencher::black_box(x), 23 | bencher::black_box(y))))); 24 | } 25 | 26 | pub fn run_u8_large u8>(b: &mut Bencher, f: F) { 27 | b.iter(|| gcd::test_util::run_u8(u8::max_value() / 3 * 2, u8::max_value(), 28 | |x, y| bencher::black_box(f(bencher::black_box(x), 29 | bencher::black_box(y))))); 30 | } 31 | 32 | fn u08_small_euclid_recursive(b: &mut Bencher) { 33 | run_u8_small(b, gcd::euclid::recursive) 34 | } 35 | 36 | fn u08_small_euclid_iterative(b: &mut Bencher) { 37 | run_u8_small(b, gcd::euclid::iterative) 38 | } 39 | 40 | fn u08_small_steins_recursive(b: &mut Bencher) { 41 | run_u8_small(b, gcd::steins::recursive) 42 | } 43 | 44 | fn u08_small_steins_iterative(b: &mut Bencher) { 45 | run_u8_small(b, gcd::steins::iterative) 46 | } 47 | 48 | fn u08_small_steins_iterative_xor(b: &mut Bencher) { 49 | run_u8_small(b, gcd::steins::iterative_xor) 50 | } 51 | 52 | 53 | benchmark_group!(u08_small_g, 54 | u08_small_euclid_recursive, 55 | u08_small_euclid_iterative, 56 | u08_small_steins_recursive, 57 | u08_small_steins_iterative, 58 | u08_small_steins_iterative_xor 59 | ); 60 | 61 | fn u08_mid_euclid_recursive(b: &mut Bencher) { 62 | run_u8_mid(b, gcd::euclid::recursive) 63 | } 64 | 65 | fn u08_mid_euclid_iterative(b: &mut Bencher) { 66 | run_u8_mid(b, gcd::euclid::iterative) 67 | } 68 | 69 | fn u08_mid_steins_recursive(b: &mut Bencher) { 70 | run_u8_mid(b, gcd::steins::recursive) 71 | } 72 | 73 | fn u08_mid_steins_iterative(b: &mut Bencher) { 74 | run_u8_mid(b, gcd::steins::iterative) 75 | } 76 | 77 | fn u08_mid_steins_iterative_xor(b: &mut Bencher) { 78 | run_u8_mid(b, gcd::steins::iterative_xor) 79 | } 80 | 81 | 82 | benchmark_group!(u08_mid_g, 83 | u08_mid_euclid_recursive, 84 | u08_mid_euclid_iterative, 85 | u08_mid_steins_recursive, 86 | u08_mid_steins_iterative, 87 | u08_mid_steins_iterative_xor 88 | ); 89 | 90 | 91 | fn u08_large_euclid_recursive(b: &mut Bencher) { 92 | run_u8_large(b, gcd::euclid::recursive) 93 | } 94 | 95 | fn u08_large_euclid_iterative(b: &mut Bencher) { 96 | run_u8_large(b, gcd::euclid::iterative) 97 | } 98 | 99 | fn u08_large_steins_recursive(b: &mut Bencher) { 100 | run_u8_large(b, gcd::steins::recursive) 101 | } 102 | 103 | fn u08_large_steins_iterative(b: &mut Bencher) { 104 | run_u8_large(b, gcd::steins::iterative) 105 | } 106 | 107 | fn u08_large_steins_iterative_xor(b: &mut Bencher) { 108 | run_u8_large(b, gcd::steins::iterative_xor) 109 | } 110 | 111 | 112 | benchmark_group!(u08_large_g, 113 | u08_large_euclid_recursive, 114 | u08_large_euclid_iterative, 115 | u08_large_steins_recursive, 116 | u08_large_steins_iterative, 117 | u08_large_steins_iterative_xor 118 | ); 119 | 120 | 121 | 122 | 123 | pub fn run_u16_small u16>(b: &mut Bencher, f: F) { 124 | b.iter(|| gcd::test_util::run_u16(0, u16::max_value() / 3, 125 | |x, y| bencher::black_box(f(bencher::black_box(x), 126 | bencher::black_box(y))))); 127 | } 128 | 129 | pub fn run_u16_mid u16>(b: &mut Bencher, f: F) { 130 | b.iter(|| gcd::test_util::run_u16(u16::max_value() / 3, u16::max_value() / 3 * 2, 131 | |x, y| bencher::black_box(f(bencher::black_box(x), 132 | bencher::black_box(y))))); 133 | } 134 | 135 | pub fn run_u16_large u16>(b: &mut Bencher, f: F) { 136 | b.iter(|| gcd::test_util::run_u16(u16::max_value() / 6 * 5 , u16::max_value(), 137 | |x, y| bencher::black_box(f(bencher::black_box(x), 138 | bencher::black_box(y))))); 139 | } 140 | 141 | fn u16_small_euclid_recursive(b: &mut Bencher) { 142 | run_u16_small(b, gcd::euclid::recursive) 143 | } 144 | 145 | fn u16_small_euclid_iterative(b: &mut Bencher) { 146 | run_u16_small(b, gcd::euclid::iterative) 147 | } 148 | 149 | fn u16_small_steins_recursive(b: &mut Bencher) { 150 | run_u16_small(b, gcd::steins::recursive) 151 | } 152 | 153 | fn u16_small_steins_iterative(b: &mut Bencher) { 154 | run_u16_small(b, gcd::steins::iterative) 155 | } 156 | 157 | fn u16_small_steins_iterative_xor(b: &mut Bencher) { 158 | run_u16_small(b, gcd::steins::iterative_xor) 159 | } 160 | /* 161 | 162 | benchmark_group!(u16_small_g, 163 | u16_small_euclid_recursive, 164 | u16_small_euclid_iterative, 165 | u16_small_steins_recursive, 166 | u16_small_steins_iterative, 167 | u16_small_steins_iterative_xor 168 | ); 169 | 170 | fn u16_mid_euclid_recursive(b: &mut Bencher) { 171 | run_u16_mid(b, gcd::euclid::recursive) 172 | } 173 | 174 | fn u16_mid_euclid_iterative(b: &mut Bencher) { 175 | run_u16_mid(b, gcd::euclid::iterative) 176 | } 177 | 178 | fn u16_mid_steins_recursive(b: &mut Bencher) { 179 | run_u16_mid(b, gcd::steins::recursive) 180 | } 181 | 182 | fn u16_mid_steins_iterative(b: &mut Bencher) { 183 | run_u16_mid(b, gcd::steins::iterative) 184 | } 185 | 186 | fn u16_mid_steins_iterative_xor(b: &mut Bencher) { 187 | run_u16_mid(b, gcd::steins::iterative_xor) 188 | } 189 | 190 | 191 | benchmark_group!(u16_mid_g, 192 | u16_mid_euclid_recursive, 193 | u16_mid_euclid_iterative, 194 | u16_mid_steins_recursive, 195 | u16_mid_steins_iterative, 196 | u16_mid_steins_iterative_xor 197 | ); 198 | 199 | 200 | fn u16_large_euclid_recursive(b: &mut Bencher) { 201 | run_u16_large(b, gcd::euclid::recursive) 202 | } 203 | 204 | fn u16_large_euclid_iterative(b: &mut Bencher) { 205 | run_u16_large(b, gcd::euclid::iterative) 206 | } 207 | 208 | fn u16_large_steins_recursive(b: &mut Bencher) { 209 | run_u16_large(b, gcd::steins::recursive) 210 | } 211 | 212 | fn u16_large_steins_iterative(b: &mut Bencher) { 213 | run_u16_large(b, gcd::steins::iterative) 214 | } 215 | 216 | fn u16_large_steins_iterative_xor(b: &mut Bencher) { 217 | run_u16_large(b, gcd::steins::iterative_xor) 218 | } 219 | 220 | benchmark_group!(u16_large_g, 221 | //u16_large_euclid_recursive, 222 | //u16_large_euclid_iterative, 223 | //u16_large_steins_recursive, 224 | //u16_large_steins_iterative, 225 | u16_large_steins_iterative_xor 226 | ); 227 | */ 228 | 229 | 230 | benchmark_main!(u08_small_g, u08_mid_g, u08_large_g); 231 | -------------------------------------------------------------------------------- /benches/morton.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate bencher; 3 | 4 | extern crate bitwise; 5 | 6 | use bencher::Bencher; 7 | 8 | use std::fmt::Debug; 9 | use bitwise::word::Word; 10 | use bitwise::word::morton; 11 | 12 | use bitwise::word::morton::testing_utils::*; 13 | 14 | struct BMI2Encode2D; 15 | impl RunnerFn for BMI2Encode2D { 16 | fn run(&self, v: T) { 17 | bencher::black_box(morton::bmi2::encode_2d::(bencher::black_box(v), 18 | bencher::black_box(v))); 19 | } 20 | } 21 | 22 | fn encode_2d_u08_bmi2(b: &mut Bencher) { 23 | b.iter(|| Runner::run_u8(&BMI2Encode2D {})); 24 | } 25 | fn encode_2d_u16_bmi2(b: &mut Bencher) { 26 | b.iter(|| Runner::run_u16(&BMI2Encode2D {})); 27 | } 28 | fn encode_2d_u32_bmi2(b: &mut Bencher) { 29 | b.iter(|| Runner::run_u32(&BMI2Encode2D {})); 30 | } 31 | fn encode_2d_u64_bmi2(b: &mut Bencher) { 32 | b.iter(|| Runner::run_u64(&BMI2Encode2D {})); 33 | } 34 | 35 | 36 | struct LUTEncode2D; 37 | impl RunnerFn for LUTEncode2D { 38 | fn run(&self, v: T) { 39 | bencher::black_box(morton::lut::encode_2d::(bencher::black_box(v), 40 | bencher::black_box(v))); 41 | } 42 | } 43 | 44 | fn encode_2d_u08_lut(b: &mut Bencher) { 45 | b.iter(|| Runner::run_u8(&LUTEncode2D {})); 46 | } 47 | fn encode_2d_u16_lut(b: &mut Bencher) { 48 | b.iter(|| Runner::run_u16(&LUTEncode2D {})); 49 | } 50 | fn encode_2d_u32_lut(b: &mut Bencher) { 51 | b.iter(|| Runner::run_u32(&LUTEncode2D {})); 52 | } 53 | fn encode_2d_u64_lut(b: &mut Bencher) { 54 | b.iter(|| Runner::run_u64(&LUTEncode2D {})); 55 | } 56 | 57 | 58 | struct BITMASKEncode2D; 59 | impl RunnerFn for BITMASKEncode2D { 60 | fn run(&self, v: T) { 61 | bencher::black_box(morton::bitmask::encode_2d::(bencher::black_box(v), 62 | bencher::black_box(v))); 63 | } 64 | } 65 | 66 | fn encode_2d_u08_bitmask(b: &mut Bencher) { 67 | b.iter(|| Runner::run_u8(&BITMASKEncode2D {})); 68 | } 69 | fn encode_2d_u16_bitmask(b: &mut Bencher) { 70 | b.iter(|| Runner::run_u16(&BITMASKEncode2D {})); 71 | } 72 | fn encode_2d_u32_bitmask(b: &mut Bencher) { 73 | b.iter(|| Runner::run_u32(&BITMASKEncode2D {})); 74 | } 75 | fn encode_2d_u64_bitmask(b: &mut Bencher) { 76 | b.iter(|| Runner::run_u64(&BITMASKEncode2D {})); 77 | } 78 | 79 | 80 | struct Encode2D; 81 | impl RunnerFn for Encode2D { 82 | fn run(&self, v: T) { 83 | bencher::black_box(morton::encode_2d::(bencher::black_box(v), bencher::black_box(v))); 84 | } 85 | } 86 | 87 | fn encode_2d_u08(b: &mut Bencher) { 88 | b.iter(|| Runner::run_u8(&Encode2D {})); 89 | } 90 | fn encode_2d_u16(b: &mut Bencher) { 91 | b.iter(|| Runner::run_u16(&Encode2D {})); 92 | } 93 | fn encode_2d_u32(b: &mut Bencher) { 94 | b.iter(|| Runner::run_u32(&Encode2D {})); 95 | } 96 | fn encode_2d_u64(b: &mut Bencher) { 97 | b.iter(|| Runner::run_u64(&Encode2D {})); 98 | } 99 | 100 | 101 | struct BMI2Decode2D; 102 | impl RunnerFn for BMI2Decode2D { 103 | fn run(&self, v: T) { 104 | bencher::black_box(morton::bmi2::decode_2d::(bencher::black_box(v))); 105 | } 106 | } 107 | 108 | fn decode_2d_u08_bmi2(b: &mut Bencher) { 109 | b.iter(|| Runner::run_u8(&BMI2Decode2D {})); 110 | } 111 | fn decode_2d_u16_bmi2(b: &mut Bencher) { 112 | b.iter(|| Runner::run_u16(&BMI2Decode2D {})); 113 | } 114 | fn decode_2d_u32_bmi2(b: &mut Bencher) { 115 | b.iter(|| Runner::run_u32(&BMI2Decode2D {})); 116 | } 117 | fn decode_2d_u64_bmi2(b: &mut Bencher) { 118 | b.iter(|| Runner::run_u64(&BMI2Decode2D {})); 119 | } 120 | 121 | 122 | struct LUTDecode2D; 123 | impl RunnerFn for LUTDecode2D { 124 | fn run(&self, v: T) { 125 | bencher::black_box(morton::lut::decode_2d::(bencher::black_box(v))); 126 | } 127 | } 128 | 129 | fn decode_2d_u08_lut(b: &mut Bencher) { 130 | b.iter(|| Runner::run_u8(&LUTDecode2D {})); 131 | } 132 | fn decode_2d_u16_lut(b: &mut Bencher) { 133 | b.iter(|| Runner::run_u16(&LUTDecode2D {})); 134 | } 135 | fn decode_2d_u32_lut(b: &mut Bencher) { 136 | b.iter(|| Runner::run_u32(&LUTDecode2D {})); 137 | } 138 | fn decode_2d_u64_lut(b: &mut Bencher) { 139 | b.iter(|| Runner::run_u64(&LUTDecode2D {})); 140 | } 141 | 142 | 143 | struct BITMASKDecode2D; 144 | impl RunnerFn for BITMASKDecode2D { 145 | fn run(&self, v: T) { 146 | bencher::black_box(morton::bitmask::decode_2d::(bencher::black_box(v))); 147 | } 148 | } 149 | 150 | fn decode_2d_u08_bitmask(b: &mut Bencher) { 151 | b.iter(|| Runner::run_u8(&BITMASKDecode2D {})); 152 | } 153 | fn decode_2d_u16_bitmask(b: &mut Bencher) { 154 | b.iter(|| Runner::run_u16(&BITMASKDecode2D {})); 155 | } 156 | fn decode_2d_u32_bitmask(b: &mut Bencher) { 157 | b.iter(|| Runner::run_u32(&BITMASKDecode2D {})); 158 | } 159 | fn decode_2d_u64_bitmask(b: &mut Bencher) { 160 | b.iter(|| Runner::run_u64(&BITMASKDecode2D {})); 161 | } 162 | 163 | struct Decode2D; 164 | impl RunnerFn for Decode2D { 165 | fn run(&self, v: T) { 166 | bencher::black_box(morton::decode_2d::(bencher::black_box(v))); 167 | } 168 | } 169 | 170 | fn decode_2d_u08(b: &mut Bencher) { 171 | b.iter(|| Runner::run_u8(&Decode2D {})); 172 | } 173 | fn decode_2d_u16(b: &mut Bencher) { 174 | b.iter(|| Runner::run_u16(&Decode2D {})); 175 | } 176 | fn decode_2d_u32(b: &mut Bencher) { 177 | b.iter(|| Runner::run_u32(&Decode2D {})); 178 | } 179 | fn decode_2d_u64(b: &mut Bencher) { 180 | b.iter(|| Runner::run_u64(&Decode2D {})); 181 | } 182 | 183 | 184 | struct BMI2Encode3D; 185 | impl RunnerFn for BMI2Encode3D { 186 | fn run(&self, v: T) { 187 | bencher::black_box(morton::bmi2::encode_3d::(bencher::black_box(v), 188 | bencher::black_box(v), 189 | bencher::black_box(v))); 190 | } 191 | } 192 | 193 | fn encode_3d_u08_bmi2(b: &mut Bencher) { 194 | b.iter(|| Runner::run_u8(&BMI2Encode3D {})); 195 | } 196 | fn encode_3d_u16_bmi2(b: &mut Bencher) { 197 | b.iter(|| Runner::run_u16(&BMI2Encode3D {})); 198 | } 199 | fn encode_3d_u32_bmi2(b: &mut Bencher) { 200 | b.iter(|| Runner::run_u32(&BMI2Encode3D {})); 201 | } 202 | fn encode_3d_u64_bmi2(b: &mut Bencher) { 203 | b.iter(|| Runner::run_u64(&BMI2Encode3D {})); 204 | } 205 | 206 | 207 | struct LUTEncode3D; 208 | impl RunnerFn for LUTEncode3D { 209 | fn run(&self, v: T) { 210 | bencher::black_box(morton::lut::encode_3d::(bencher::black_box(v), 211 | bencher::black_box(v), 212 | bencher::black_box(v))); 213 | } 214 | } 215 | 216 | fn encode_3d_u08_lut(b: &mut Bencher) { 217 | b.iter(|| Runner::run_u8(&LUTEncode3D {})); 218 | } 219 | fn encode_3d_u16_lut(b: &mut Bencher) { 220 | b.iter(|| Runner::run_u16(&LUTEncode3D {})); 221 | } 222 | fn encode_3d_u32_lut(b: &mut Bencher) { 223 | b.iter(|| Runner::run_u32(&LUTEncode3D {})); 224 | } 225 | fn encode_3d_u64_lut(b: &mut Bencher) { 226 | b.iter(|| Runner::run_u64(&LUTEncode3D {})); 227 | } 228 | 229 | 230 | struct BITMASKEncode3D; 231 | impl RunnerFn for BITMASKEncode3D { 232 | fn run(&self, v: T) { 233 | bencher::black_box(morton::bitmask::encode_3d::(bencher::black_box(v), 234 | bencher::black_box(v), 235 | bencher::black_box(v))); 236 | } 237 | } 238 | 239 | fn encode_3d_u08_bitmask(b: &mut Bencher) { 240 | b.iter(|| Runner::run_u8(&BITMASKEncode3D {})); 241 | } 242 | fn encode_3d_u16_bitmask(b: &mut Bencher) { 243 | b.iter(|| Runner::run_u16(&BITMASKEncode3D {})); 244 | } 245 | fn encode_3d_u32_bitmask(b: &mut Bencher) { 246 | b.iter(|| Runner::run_u32(&BITMASKEncode3D {})); 247 | } 248 | fn encode_3d_u64_bitmask(b: &mut Bencher) { 249 | b.iter(|| Runner::run_u64(&BITMASKEncode3D {})); 250 | } 251 | 252 | 253 | struct Encode3D; 254 | impl RunnerFn for Encode3D { 255 | fn run(&self, v: T) { 256 | bencher::black_box(morton::encode_3d::(bencher::black_box(v), 257 | bencher::black_box(v), 258 | bencher::black_box(v))); 259 | } 260 | } 261 | 262 | fn encode_3d_u08(b: &mut Bencher) { 263 | b.iter(|| Runner::run_u8(&Encode3D {})); 264 | } 265 | fn encode_3d_u16(b: &mut Bencher) { 266 | b.iter(|| Runner::run_u16(&Encode3D {})); 267 | } 268 | fn encode_3d_u32(b: &mut Bencher) { 269 | b.iter(|| Runner::run_u32(&Encode3D {})); 270 | } 271 | fn encode_3d_u64(b: &mut Bencher) { 272 | b.iter(|| Runner::run_u64(&Encode3D {})); 273 | } 274 | 275 | 276 | struct BMI3Decode3D; 277 | impl RunnerFn for BMI3Decode3D { 278 | fn run(&self, v: T) { 279 | bencher::black_box(morton::bmi2::decode_3d::(bencher::black_box(v))); 280 | } 281 | } 282 | 283 | fn decode_3d_u08_bmi2(b: &mut Bencher) { 284 | b.iter(|| Runner::run_u8(&BMI3Decode3D {})); 285 | } 286 | fn decode_3d_u16_bmi2(b: &mut Bencher) { 287 | b.iter(|| Runner::run_u16(&BMI3Decode3D {})); 288 | } 289 | fn decode_3d_u32_bmi2(b: &mut Bencher) { 290 | b.iter(|| Runner::run_u32(&BMI3Decode3D {})); 291 | } 292 | fn decode_3d_u64_bmi2(b: &mut Bencher) { 293 | b.iter(|| Runner::run_u64(&BMI3Decode3D {})); 294 | } 295 | 296 | 297 | struct LUTDecode3D; 298 | impl RunnerFn for LUTDecode3D { 299 | fn run(&self, v: T) { 300 | bencher::black_box(morton::lut::decode_3d::(bencher::black_box(v))); 301 | } 302 | } 303 | 304 | fn decode_3d_u08_lut(b: &mut Bencher) { 305 | b.iter(|| Runner::run_u8(&LUTDecode3D {})); 306 | } 307 | fn decode_3d_u16_lut(b: &mut Bencher) { 308 | b.iter(|| Runner::run_u16(&LUTDecode3D {})); 309 | } 310 | fn decode_3d_u32_lut(b: &mut Bencher) { 311 | b.iter(|| Runner::run_u32(&LUTDecode3D {})); 312 | } 313 | fn decode_3d_u64_lut(b: &mut Bencher) { 314 | b.iter(|| Runner::run_u64(&LUTDecode3D {})); 315 | } 316 | 317 | 318 | struct BITMASKDecode3D; 319 | impl RunnerFn for BITMASKDecode3D { 320 | fn run(&self, v: T) { 321 | bencher::black_box(morton::bitmask::decode_3d::(bencher::black_box(v))); 322 | } 323 | } 324 | 325 | fn decode_3d_u08_bitmask(b: &mut Bencher) { 326 | b.iter(|| Runner::run_u8(&BITMASKDecode3D {})); 327 | } 328 | fn decode_3d_u16_bitmask(b: &mut Bencher) { 329 | b.iter(|| Runner::run_u16(&BITMASKDecode3D {})); 330 | } 331 | fn decode_3d_u32_bitmask(b: &mut Bencher) { 332 | b.iter(|| Runner::run_u32(&BITMASKDecode3D {})); 333 | } 334 | fn decode_3d_u64_bitmask(b: &mut Bencher) { 335 | b.iter(|| Runner::run_u64(&BITMASKDecode3D {})); 336 | } 337 | 338 | struct Decode3D; 339 | impl RunnerFn for Decode3D { 340 | fn run(&self, v: T) { 341 | bencher::black_box(morton::decode_3d::(bencher::black_box(v))); 342 | } 343 | } 344 | 345 | fn decode_3d_u08(b: &mut Bencher) { 346 | b.iter(|| Runner::run_u8(&Decode3D {})); 347 | } 348 | fn decode_3d_u16(b: &mut Bencher) { 349 | b.iter(|| Runner::run_u16(&Decode3D {})); 350 | } 351 | fn decode_3d_u32(b: &mut Bencher) { 352 | b.iter(|| Runner::run_u32(&Decode3D {})); 353 | } 354 | fn decode_3d_u64(b: &mut Bencher) { 355 | b.iter(|| Runner::run_u64(&Decode3D {})); 356 | } 357 | 358 | 359 | benchmark_group!(encode_2d_u08_g, 360 | encode_2d_u08_bmi2, 361 | encode_2d_u08_lut, 362 | encode_2d_u08_bitmask, 363 | encode_2d_u08); 364 | benchmark_group!(decode_2d_u08_g, 365 | decode_2d_u08_bmi2, 366 | decode_2d_u08_lut, 367 | decode_2d_u08_bitmask, 368 | decode_2d_u08); 369 | benchmark_group!(encode_3d_u08_g, 370 | encode_3d_u08_bmi2, 371 | encode_3d_u08_lut, 372 | encode_3d_u08_bitmask, 373 | encode_3d_u08); 374 | benchmark_group!(decode_3d_u08_g, 375 | decode_3d_u08_bmi2, 376 | decode_3d_u08_lut, 377 | decode_3d_u08_bitmask, 378 | decode_3d_u08); 379 | 380 | benchmark_group!(encode_2d_u16_g, 381 | encode_2d_u16_bmi2, 382 | encode_2d_u16_lut, 383 | encode_2d_u16_bitmask, 384 | encode_2d_u16); 385 | benchmark_group!(decode_2d_u16_g, 386 | decode_2d_u16_bmi2, 387 | decode_2d_u16_lut, 388 | decode_2d_u16_bitmask, 389 | decode_2d_u16); 390 | benchmark_group!(encode_3d_u16_g, 391 | encode_3d_u16_bmi2, 392 | encode_3d_u16_lut, 393 | encode_3d_u16_bitmask, 394 | encode_3d_u16); 395 | benchmark_group!(decode_3d_u16_g, 396 | decode_3d_u16_bmi2, 397 | decode_3d_u16_lut, 398 | decode_3d_u16_bitmask, 399 | decode_3d_u16); 400 | 401 | benchmark_group!(encode_2d_u32_g, 402 | encode_2d_u32_bmi2, 403 | encode_2d_u32_lut, 404 | encode_2d_u32_bitmask, 405 | encode_2d_u32); 406 | benchmark_group!(decode_2d_u32_g, 407 | decode_2d_u32_bmi2, 408 | decode_2d_u32_lut, 409 | decode_2d_u32_bitmask, 410 | decode_2d_u32); 411 | benchmark_group!(encode_3d_u32_g, 412 | encode_3d_u32_bmi2, 413 | encode_3d_u32_lut, 414 | encode_3d_u32_bitmask, 415 | encode_3d_u32); 416 | benchmark_group!(decode_3d_u32_g, 417 | decode_3d_u32_bmi2, 418 | decode_3d_u32_lut, 419 | decode_3d_u32_bitmask, 420 | decode_3d_u32); 421 | 422 | benchmark_group!(encode_2d_u64_g, 423 | encode_2d_u64_bmi2, 424 | encode_2d_u64_lut, 425 | encode_2d_u64_bitmask, 426 | encode_2d_u64); 427 | benchmark_group!(decode_2d_u64_g, 428 | decode_2d_u64_bmi2, 429 | decode_2d_u64_lut, 430 | decode_2d_u64_bitmask, 431 | decode_2d_u64); 432 | benchmark_group!(encode_3d_u64_g, 433 | encode_3d_u64_bmi2, 434 | encode_3d_u64_lut, 435 | encode_3d_u64_bitmask, 436 | encode_3d_u64); 437 | benchmark_group!(decode_3d_u64_g, 438 | decode_3d_u64_bmi2, 439 | decode_3d_u64_lut, 440 | decode_3d_u64_bitmask, 441 | decode_3d_u64); 442 | 443 | 444 | benchmark_main!(encode_2d_u08_g, 445 | decode_2d_u08_g, 446 | encode_3d_u08_g, 447 | decode_3d_u08_g, 448 | encode_2d_u16_g, 449 | decode_2d_u16_g, 450 | encode_3d_u16_g, 451 | decode_3d_u16_g, 452 | encode_2d_u32_g, 453 | decode_2d_u32_g, 454 | encode_3d_u32_g, 455 | decode_3d_u32_g, 456 | encode_2d_u64_g, 457 | decode_2d_u64_g, 458 | encode_3d_u64_g, 459 | decode_3d_u64_g); 460 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate rustc_version; 2 | use rustc_version::{version, version_meta, Channel}; 3 | 4 | fn main() { 5 | // Assert we haven't travelled back in time 6 | assert!(version().unwrap().major >= 1); 7 | 8 | // Set cfg flags depending on release channel 9 | match version_meta().unwrap().channel { 10 | Channel::Nightly => { 11 | println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY"); 12 | }, 13 | _ => {} 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | doc-valid-idents = ["ARMv5", "ARMv6", "ARMv7", "ARMv8", "x86_64", "PowerPC"] 2 | single-char-binding-names-threshold = 6 -------------------------------------------------------------------------------- /examples/readme.rs: -------------------------------------------------------------------------------- 1 | extern crate bitwise; 2 | use bitwise::word::*; 3 | 4 | fn main() { 5 | let u = outer_perfect_shuffle(0b_1001_1111u8); 6 | let v = inner_perfect_shuffle(0b_1001_1111u8); 7 | let w = u.copy_bit(4u8, v, 3u8); 8 | assert_eq!(w.parallel_bits_deposit(u), 0b1001_0011u8); 9 | } 10 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2017 Gonzalo Brito Gadeschi 2 | Copyright (c) Matthew Firoravante 3 | Copyright (c) 2016 Jeroen Baert 4 | 5 | Permission is hereby granted, free of charge, to any 6 | person obtaining a copy of this software and associated 7 | documentation files (the "Software"), to deal in the 8 | Software without restriction, including without 9 | limitation the rights to use, copy, modify, merge, 10 | publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software 12 | is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions 17 | of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 20 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 21 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 22 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 23 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 26 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Portable high-level bitwise manipulation algorithms 2 | 3 | [![crates.io version][crate-shield]][crate] [![Travis build status][travis-shield]][travis] [![Coveralls.io code coverage][coveralls-shield]][coveralls] [![Docs][docs-shield]][docs] [![License][license-shield]][license] 4 | 5 | > We do what we must because we can. 6 | 7 | The algorithms: 8 | 9 | - have descriptive names to ease reading code that performs bit manipulations, 10 | - often optimize to perfect assembly code (and _always_ on nightly by using 11 | the [bitintr][bitintr_link] crate), 12 | - works on ~~stable~~ unstable only :( due to specialization for now. 13 | 14 | ## Example 15 | 16 | ```rust 17 | extern crate bitwise; 18 | use bitwise::word::*; 19 | 20 | fn main() { 21 | let u = outer_perfect_shuffle(0b_1001_1111u8); 22 | let v = inner_perfect_shuffle(0b_1001_1111u8); 23 | let w = u.copy_bit(4u8, v, 3u8); 24 | assert_eq!(w.parallel_bits_deposit(u), 0b_1001_0011u8); 25 | } 26 | ``` 27 | 28 | ## Supported compilers 29 | 30 | > The minimum required rustc version is >= **1.13.0**. 31 | 32 | Requires unstable for now. 33 | 34 | ## Performance 35 | 36 | Some algorithms like the Morton Z-Curve encoding/decoding routines switch 37 | implementation at compile-time depending on target features (like BMI2 support). 38 | 39 | ## License 40 | 41 | Licensed under the [MIT license][license]. 42 | 43 | ## Acknowledgments 44 | 45 | The giants that came before us: 46 | 47 | - Matthew Fioravante's 48 | [N3864 A constexpr bitwise operations library for C++][n3864_link] proposal 49 | and accompanying library: [stdcxx-bitops][stdcxx_bitops_link]. 50 | - Henry S. Warren's [Hacker's Delight][hackers_delight_link]. 51 | - Jeroen Baert's [libmorton][libmorton_link]. 52 | - The [Chess Programming Wiki][chess_programming_wiki_link], in particular 53 | the [bit-twiddling][chess_programming_bit_twiddling_link] section. 54 | - [Real-Time Collision Detection][real_time_collision_detection_link]. 55 | - My own's [bitintr][bitintr_link] library. 56 | - Jasper Neumann's [programming pages][jasper_neumann_site_link]. 57 | - Jörg Arndt's [Matters Computational: Ideas, Algorithms, Source Code][matters_computational_link]. 58 | 59 | ## Contribution 60 | 61 | Yes please! Just note that all contributions shall be licensed as above without 62 | any additional terms or conditions. The following people have contributed code to this library: 63 | 64 | - [Gonzalo Brito Gadeschi](https://github.com/gnzlbg) (main author). 65 | - [Brian L. Troutwine](https://github.com/blt). 66 | 67 | 68 | [travis-shield]: https://img.shields.io/travis/gnzlbg/bitwise.svg?style=flat-square 69 | [travis]: https://travis-ci.org/gnzlbg/bitwise 70 | [coveralls-shield]: https://img.shields.io/coveralls/gnzlbg/bitwise.svg?style=flat-square 71 | [coveralls]: https://coveralls.io/github/gnzlbg/bitwise 72 | [docs-shield]: https://img.shields.io/badge/docs-online-blue.svg?style=flat-square 73 | [docs]: https://gnzlbg.github.io/bitwise 74 | [license-shield]: https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square 75 | [license]: https://github.com/gnzlbg/bitwise/blob/master/license.md 76 | [crate-shield]: https://img.shields.io/crates/v/bitwise.svg?style=flat-square 77 | [crate]: https://crates.io/crates/bitwise 78 | [bitintr_link]: https://github.com/gnzlbg/bitintr 79 | [n3864_link]: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3864.html 80 | [stdcxx_bitops_link]: https://github.com/fmatthew5876/stdcxx-bitops 81 | [libmorton_link]: https://github.com/Forceflow/libmorton 82 | [chess_programming_wiki_link]: https://www.chessprogramming.org 83 | [chess_programming_bit_twiddling_link]: https://www.chessprogramming.org/Bit-Twiddling 84 | [real_time_collision_detection_link]: https://realtimecollisiondetection.net/ 85 | [hackers_delight_link]: https://hackersdelight.org/ 86 | [jasper_neumann_site_link]: https://programming.sirrida.de/index.php 87 | [matters_computational_link]: https://www.jjj.de/fxt/fxtbook.pdf 88 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `bitwise` offers portable high-level manipulation algorithms 2 | //! ([@github](https://github.com/gnzlbg/bitwise), 3 | //! [@crates.io](https://crates.io/crates/bitwise)). 4 | //! 5 | //! The algorithms: 6 | //! 7 | //! - have descriptive names to ease reading code that performs bit manipulations, 8 | //! - often optimize to perfect assembly code (and _always_ on nightly by using 9 | //! the [`bitintr`](https://crates.io/crates/bitintr) crate), 10 | //! - works on ~~stable~~ unstable only :( due to specialization for now. 11 | //! 12 | //! ## Example 13 | //! 14 | //! ```rust 15 | //! extern crate bitwise; 16 | //! use bitwise::word::*; 17 | //! 18 | //! fn main() { 19 | //! let u = outer_perfect_shuffle(0b_1001_1111u8); 20 | //! let v = inner_perfect_shuffle(0b_1001_1111u8); 21 | //! let w = u.copy_bit(4u8, v, 3u8); 22 | //! assert_eq!(w.parallel_bits_deposit(u), 0b_1001_0011u8); 23 | //! } 24 | //! ``` 25 | 26 | #![cfg_attr(RUSTC_IS_NIGHTLY, feature(specialization))] 27 | #![cfg_attr(RUSTC_IS_NIGHTLY, feature(cfg_target_feature))] 28 | #![cfg_attr(RUSTC_IS_NIGHTLY, feature(test))] 29 | 30 | #![no_std] 31 | extern crate core as std; 32 | 33 | #[cfg(RUSTC_IS_NIGHTLY)] 34 | extern crate test; 35 | 36 | #[cfg(test)] 37 | extern crate quickcheck; 38 | 39 | /// Low-level bitwise manipulation intrinsics. 40 | pub extern crate bitintr; 41 | 42 | pub mod word; 43 | 44 | pub use word::*; 45 | -------------------------------------------------------------------------------- /src/word/align_down.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, UnsignedWord, ToWord, IsPow2}; 2 | 3 | /// Align `x` down to `alignment`. 4 | /// 5 | /// Returns `n`, where `n` is the greatest number <= `x` 6 | /// and `is_aligned(n, alignment)`. 7 | /// 8 | /// # Panics 9 | /// 10 | /// `alignment` must be a power of two. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// assert_eq!(2.align_down(1u8), 2); 18 | /// assert_eq!(align_down(2, 2u8), 2); 19 | /// assert_eq!(2.align_down(4u8), 0); 20 | /// assert_eq!(2.align_down(8u8), 0); 21 | /// 22 | /// assert_eq!(3.align_down(1u8), 3); 23 | /// assert_eq!(3.align_down(2u8), 2); 24 | /// assert_eq!(3.align_down(4u8), 0); 25 | /// assert_eq!(3.align_down(8u8), 0); 26 | /// 27 | /// assert_eq!(4.align_down(1u8), 4); 28 | /// assert_eq!(4.align_down(2u8), 4); 29 | /// assert_eq!(4.align_down(4u8), 4); 30 | /// assert_eq!(4.align_down(8u8), 0); 31 | /// ``` 32 | #[inline] 33 | pub fn align_down(x: T, alignment: U) -> T { 34 | debug_assert!(alignment.is_pow2()); 35 | (x & (!(alignment - U::one())).to()).to() 36 | } 37 | 38 | /// Method version of [`align_down`](fn.align_down.html). 39 | pub trait AlignDown { 40 | #[inline] 41 | fn align_down(self, U) -> Self; 42 | } 43 | 44 | impl AlignDown for T { 45 | #[inline] 46 | fn align_down(self, u: U) -> Self { 47 | align_down(self, u) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/word/align_up.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, UnsignedWord, ToWord, IsPow2}; 2 | 3 | /// Align `x` up to `alignment`. 4 | /// 5 | /// Returns `n`, where `n` is the least number >= `x` 6 | /// and `is_aligned(n, alignment)`. 7 | /// 8 | /// # Panics 9 | /// 10 | /// `alignment` must be a power of two. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// assert_eq!(2.align_up(1u8), 2); 18 | /// assert_eq!(align_up(2, 2u8), 2); 19 | /// assert_eq!(2.align_up(4u8), 4); 20 | /// assert_eq!(2.align_up(8u8), 8); 21 | /// 22 | /// assert_eq!(3.align_up(1u8), 3); 23 | /// assert_eq!(3.align_up(2u8), 4); 24 | /// assert_eq!(3.align_up(4u8), 4); 25 | /// assert_eq!(3.align_up(8u8), 8); 26 | /// 27 | /// assert_eq!(4.align_up(1u8), 4); 28 | /// assert_eq!(4.align_up(2u8), 4); 29 | /// assert_eq!(4.align_up(4u8), 4); 30 | /// assert_eq!(4.align_up(8u8), 8); 31 | /// ``` 32 | #[inline] 33 | pub fn align_up(x: T, alignment: U) -> T { 34 | debug_assert!(alignment.is_pow2()); 35 | let x = x.to_unsigned(); 36 | let a = alignment - U::one(); 37 | ((x + a.to()) & (!a).to()).to() 38 | } 39 | 40 | /// Method version of [`align_up`](fn.align_up.html). 41 | pub trait AlignUp { 42 | #[inline] 43 | fn align_up(self, U) -> Self; 44 | } 45 | 46 | impl AlignUp for T { 47 | #[inline] 48 | fn align_up(self, u: U) -> Self { 49 | align_up(self, u) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/word/ceil_pow2.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Round `x` to the next power of 2. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If the next power of 2 cannot be represented by `T`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// assert_eq!(2.ceil_pow2(), 2); 15 | /// assert_eq!(ceil_pow2(3), 4); 16 | /// assert_eq!(4.ceil_pow2(), 4); 17 | /// assert_eq!(5.ceil_pow2(), 8); 18 | /// assert_eq!(6.ceil_pow2(), 8); 19 | /// assert_eq!(7.ceil_pow2(), 8); 20 | /// assert_eq!(8.ceil_pow2(), 8); 21 | /// assert_eq!(2u32.pow(30).ceil_pow2(), 2u32.pow(30)); 22 | /// assert_eq!((2u32.pow(30) + 1).ceil_pow2(), 2u32.pow(31)); 23 | /// assert_eq!(2u32.pow(31).ceil_pow2(), 2u32.pow(31)); 24 | /// // panics: 25 | /// // assert_eq!((2u32.pow(31) + 1).ceil_pow2(), 2u32.pow(32)); 26 | /// ``` 27 | #[inline] 28 | pub fn ceil_pow2(x: T) -> T { 29 | let mut x = x - T::one(); 30 | let s = T::byte_size(); 31 | x = x | (x >> T::one()); 32 | x = x | (x >> T::from_u8(2)); 33 | x = x | (x >> T::from_u8(4)); 34 | if s > T::one() { 35 | x = x | (x >> T::from_u8(8)); 36 | if s > T::from_u8(2) { 37 | x = x | (x >> T::from_u8(16)); 38 | if s > T::from_u8(4) { 39 | x = x | (x >> T::from_u8(32)); 40 | } 41 | } 42 | } 43 | x + T::one() 44 | } 45 | 46 | /// Method version of [`ceil_pow2`](fn.ceil_pow2.html). 47 | pub trait CeilPow2 { 48 | #[inline] 49 | fn ceil_pow2(self) -> Self; 50 | } 51 | 52 | impl CeilPow2 for T { 53 | #[inline] 54 | fn ceil_pow2(self) -> Self { 55 | ceil_pow2(self) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/word/clear_bit.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Clear the `bit` of `x`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1011_0010u8; 15 | /// assert_eq!(clear_bit(n, 7u8), 0b0011_0010u8); 16 | /// assert_eq!(n.clear_bit(1u8), 0b1011_0000u8); 17 | /// assert_eq!(n.clear_bit(5u8), 0b1001_0010u8); 18 | /// ``` 19 | #[inline] 20 | pub fn clear_bit(x: T, bit: U) -> T { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x & !(T::one() << bit.to()) 23 | } 24 | 25 | /// Method version of [`clear_bit`](fn.clear_bit.html). 26 | pub trait ClearBit { 27 | #[inline] 28 | fn clear_bit(self, n: U) -> Self; 29 | } 30 | 31 | impl ClearBit for T { 32 | #[inline] 33 | fn clear_bit(self, n: U) -> Self { 34 | clear_bit(self, n) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/clear_bits_geq.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Clears all bits of `x` at position >= `bit`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Intrinsics: 10 | /// - BMI 2.0: bzhi. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// assert_eq!(0b1111_0010u8.clear_bits_geq(5u8), 0b0001_0010u8); 18 | /// assert_eq!(clear_bits_geq(0b1111_0010u8, 5u8), 0b0001_0010u8); 19 | /// ``` 20 | #[inline] 21 | pub fn clear_bits_geq(x: T, bit: U) -> T { 22 | debug_assert!(T::bit_size() > bit.to()); 23 | x.bzhi(bit.to()) 24 | } 25 | 26 | /// Method version of [`clear_bits_geq`](fn.clear_bits_geq.html). 27 | pub trait ClearBitsGeq { 28 | #[inline] 29 | fn clear_bits_geq(self, n: U) -> Self; 30 | } 31 | 32 | impl ClearBitsGeq for T { 33 | #[inline] 34 | fn clear_bits_geq(self, n: U) -> Self { 35 | clear_bits_geq(self, n) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/word/clear_bits_leq.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Clears all bits of `x` at position <= `bit`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1111_0010u8; 15 | /// let s = 0b1100_0000u8; 16 | /// assert_eq!(n.clear_bits_leq(5u8), s); 17 | /// assert_eq!(clear_bits_leq(n, 5u8), s); 18 | /// ``` 19 | #[inline] 20 | pub fn clear_bits_leq(x: T, bit: U) -> T { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x & !((T::one() << (T::one() + bit.to())) - T::one()) 23 | } 24 | 25 | /// Method version of [`clear_bits_leq`](fn.clear_bits_leq.html). 26 | pub trait ClearBitsLeq { 27 | #[inline] 28 | fn clear_bits_leq(self, n: U) -> Self; 29 | } 30 | 31 | impl ClearBitsLeq for T { 32 | #[inline] 33 | fn clear_bits_leq(self, n: U) -> Self { 34 | clear_bits_leq(self, n) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/clear_least_significant_one.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Clear least significant set bit of `x`. 4 | /// 5 | /// Returns 0 if `x` is 0. 6 | /// 7 | /// # Intrinsics: 8 | /// - BMI 1.0: blsr. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// use bitwise::word::*; 14 | /// 15 | /// let n = 0b0110; 16 | /// let s = 0b0100; 17 | /// 18 | /// assert_eq!(n.clear_least_significant_one(), s); 19 | /// assert_eq!(clear_least_significant_one(n), s); 20 | /// ``` 21 | #[inline] 22 | pub fn clear_least_significant_one(x: T) -> T { 23 | x.blsr() //x & (x - T::one()) 24 | } 25 | 26 | /// Method version of [`clear_least_significant_one`](fn.clear_least_significant_one.html). 27 | pub trait ClearLeastSignificantOne { 28 | #[inline] 29 | fn clear_least_significant_one(self) -> Self; 30 | } 31 | 32 | impl ClearLeastSignificantOne for T { 33 | #[inline] 34 | fn clear_least_significant_one(self) -> Self { 35 | clear_least_significant_one(self) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/word/clear_trailing_ones.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Clear the trailing bits set of `x`. 4 | /// 5 | /// If `x` is zero, returns `0`. 6 | /// 7 | /// # Intrinsics: 8 | /// - TBM: blcfill. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// use bitwise::word::*; 14 | /// 15 | /// let n = 0b0110_1111; 16 | /// let s = 0b0110_0000; 17 | /// 18 | /// assert_eq!(n.clear_trailing_ones(), s); 19 | /// assert_eq!(clear_trailing_ones(0), 0); 20 | /// ``` 21 | #[inline] 22 | pub fn clear_trailing_ones(x: T) -> T { 23 | x.blcfill() 24 | } 25 | 26 | /// Method version of [`clear_trailing_ones`](fn.clear_trailing_ones.html). 27 | pub trait ClearTrailingOnes { 28 | #[inline] 29 | fn clear_trailing_ones(self) -> Self; 30 | } 31 | 32 | impl ClearTrailingOnes for T { 33 | #[inline] 34 | fn clear_trailing_ones(self) -> Self { 35 | clear_trailing_ones(self) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/word/copy_bit.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord, test_bit, set_bit, clear_bit}; 2 | 3 | /// Copys the `from_bit` of `x` into `y` at `to_bit`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size() or pos >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let a = 0b1011_0010u8; 15 | /// let b = 0b1001_0010u8; 16 | /// let c = 0b1111_0010u8; 17 | /// assert_eq!(a.copy_bit(5u8, b, 5u8), a); 18 | /// assert_eq!(copy_bit(a, 6u8, c, 6u8), a); 19 | /// ``` 20 | #[inline] 21 | pub fn copy_bit(x: T, from_bit: U, y: T, to_bit: U) -> T { 22 | debug_assert!(T::bit_size() > from_bit.to()); 23 | debug_assert!(T::bit_size() > to_bit.to()); 24 | if test_bit(x, from_bit) { 25 | set_bit(y, to_bit) 26 | } else { 27 | clear_bit(y, to_bit) 28 | } 29 | } 30 | 31 | /// Method version of [`copy_bit`](fn.copy_bit.html). 32 | pub trait CopyBit { 33 | #[inline] 34 | fn copy_bit(self, f: U, Self, t: U) -> Self; 35 | } 36 | 37 | impl CopyBit for T { 38 | #[inline] 39 | fn copy_bit(self, f: U, y: Self, t: U) -> Self { 40 | copy_bit(self, f, y, t) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/word/count_leading_ones.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Count the number of leading ones in the binary representation of `x`. 4 | /// 5 | /// # Keywords: 6 | /// 7 | /// Count leading ones. 8 | /// 9 | /// # Intrinsics: 10 | /// - ARMv8: cls. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// let n = 0b1111_1111_1100_1000u16; 18 | /// 19 | /// assert_eq!(n.count_leading_ones(), 10); 20 | /// assert_eq!(count_leading_ones(n), 10); 21 | /// ``` 22 | #[inline] 23 | pub fn count_leading_ones(x: T) -> T { 24 | T::leading_zeros(!x) // TODO: use ARMv8 cls intrinsic 25 | } 26 | 27 | /// Method version of [`count_leading_ones`](fn.count_leading_ones.html). 28 | pub trait CountLeadingOnes { 29 | #[inline] 30 | fn count_leading_ones(self) -> Self; 31 | } 32 | 33 | impl CountLeadingOnes for T { 34 | #[inline] 35 | fn count_leading_ones(self) -> Self { 36 | count_leading_ones(self) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/word/count_leading_zeros.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Counts the number of leading zeros in the binary representation of `x`. 4 | /// 5 | /// # Keywords: 6 | /// 7 | /// Count leading zeros. 8 | /// 9 | /// # Intrinsics: 10 | /// - ABM: lzcnt. 11 | /// - BMI 1.0: lzcnt. 12 | /// - ARMv5: clz. 13 | /// - PowerPC: cntlzd. 14 | /// - gcc/llvm builtin: `x == 0 ? mem::size_of(x) * 8 : __builtin_clz(x)`. 15 | /// 16 | /// # Examples 17 | /// 18 | /// ``` 19 | /// use bitwise::word::*; 20 | /// 21 | /// let n = 0b0010_1000u16; 22 | /// 23 | /// assert_eq!(n.count_leading_zeros(), 10); 24 | /// assert_eq!(count_leading_zeros(n), 10); 25 | /// ``` 26 | #[inline] 27 | pub fn count_leading_zeros(x: T) -> T { 28 | x.lzcnt() 29 | } 30 | 31 | /// Method version of [`count_leading_zeros`](fn.count_leading_zeros.html). 32 | pub trait CountLeadingZeros { 33 | #[inline] 34 | fn count_leading_zeros(self) -> Self; 35 | } 36 | 37 | impl CountLeadingZeros for T { 38 | #[inline] 39 | fn count_leading_zeros(self) -> Self { 40 | count_leading_zeros(self) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/word/count_ones.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Number of ones in the binary representation of `x`. 4 | /// 5 | /// # Keywords: 6 | /// 7 | /// Population count, popcount, hamming weight, sideways sum. 8 | /// 9 | /// # Intrinsics: 10 | /// - ABM: popcnt. 11 | /// - SSE4.2: popcnt. 12 | /// - NEON: vcnt. 13 | /// - PowerPC: popcntb. 14 | /// - gcc/llvm builtin: `__builtin_popcount(x)`. 15 | /// 16 | /// # Examples 17 | /// 18 | /// ``` 19 | /// use bitwise::word::*; 20 | /// 21 | /// let n = 0b0100_1100u8; 22 | /// 23 | /// assert_eq!(n.count_ones(), 3); 24 | /// assert_eq!(count_ones(n), 3); 25 | /// ``` 26 | #[inline] 27 | pub fn count_ones(x: T) -> T { 28 | x.popcnt() 29 | } 30 | 31 | /// Method version of [`count_ones`](fn.count_ones.html). 32 | pub trait CountOnes { 33 | #[inline] 34 | fn count_ones(self) -> Self; 35 | } 36 | 37 | impl CountOnes for T { 38 | #[inline] 39 | fn count_ones(self) -> Self { 40 | count_ones(self) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/word/count_trailing_ones.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Number of trailing ones in the binary representation of `x`. 4 | /// 5 | /// # Keywords: 6 | /// 7 | /// Count trailing ones. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b0010_0111u16; 15 | /// 16 | /// assert_eq!(n.count_trailing_ones(), 3); 17 | /// assert_eq!(count_trailing_ones(n), 3); 18 | /// ``` 19 | #[inline] 20 | pub fn count_trailing_ones(x: T) -> T { 21 | T::trailing_zeros(!x) 22 | } 23 | 24 | /// Method version of [`count_trailing_ones`](fn.count_trailing_ones.html). 25 | pub trait CountTrailingOnes { 26 | #[inline] 27 | fn count_trailing_ones(self) -> Self; 28 | } 29 | 30 | impl CountTrailingOnes for T { 31 | #[inline] 32 | fn count_trailing_ones(self) -> Self { 33 | count_trailing_ones(self) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/word/count_trailing_zeros.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Count the number of trailing zeros in the binary representation of `x`. 4 | /// 5 | /// # Keywords: 6 | /// 7 | /// Count trailing zeros. 8 | /// 9 | /// # Intrinsics: 10 | /// - BMI 1.0: tzcnt. 11 | /// - gcc/llvm builtin: `x == 0 ? mem::size_of(x) * 8 : __builtin_ctz(x)`. 12 | /// 13 | /// # Examples 14 | /// 15 | /// ``` 16 | /// use bitwise::word::*; 17 | /// 18 | /// let n = 0b0010_1000u16; 19 | /// 20 | /// assert_eq!(n.count_trailing_zeros(), 3); 21 | /// assert_eq!(count_trailing_zeros(n), 3); 22 | /// ``` 23 | #[inline] 24 | pub fn count_trailing_zeros(x: T) -> T { 25 | x.tzcnt() 26 | } 27 | 28 | /// Method version of [`count_trailing_zeros`](fn.count_trailing_zeros.html). 29 | 30 | pub trait CountTrailingZeros { 31 | #[inline] 32 | fn count_trailing_zeros(self) -> Self; 33 | } 34 | 35 | impl CountTrailingZeros for T { 36 | #[inline] 37 | fn count_trailing_zeros(self) -> Self { 38 | count_trailing_zeros(self) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/word/count_zeros.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Number of zeros in the binary representation of `x`. 4 | /// 5 | /// # Examples 6 | /// 7 | /// ``` 8 | /// use bitwise::word::*; 9 | /// 10 | /// let n = 0b0100_1100u8; 11 | /// 12 | /// assert_eq!(n.count_zeros(), 5); 13 | /// assert_eq!(count_zeros(n), 5); 14 | /// ``` 15 | #[inline] 16 | pub fn count_zeros(x: T) -> T { 17 | T::count_zeros(x) 18 | } 19 | 20 | /// Method version of [`count_zeros`](fn.count_zeros.html). 21 | pub trait CountZeros { 22 | #[inline] 23 | fn count_zeros(self) -> Self; 24 | } 25 | 26 | impl CountZeros for T { 27 | #[inline] 28 | fn count_zeros(self) -> Self { 29 | count_zeros(self) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/word/extract_bits.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord}; 2 | 3 | /// Extract bits [`start`, `start + length`) from `x` into the lower bits 4 | /// of the result. 5 | /// 6 | /// # Keywords: 7 | /// 8 | /// Gather bit range. 9 | /// 10 | /// # Intrinsics: 11 | /// - BMI 1.0: bextr. 12 | /// 13 | /// # Examples 14 | /// 15 | /// ``` 16 | /// use bitwise::word::*; 17 | /// 18 | /// let n = 0b1011_1110_1001_0011u16; 19 | /// 20 | /// assert_eq!(n.extract_bits(1u8, 4u8), 0b1001); 21 | /// ``` 22 | #[inline] 23 | pub fn extract_bits(x: T, start: U, length: U) -> T { 24 | x.bextr(start.to(), length.to()) 25 | } 26 | 27 | /// Method version of [`extract_bits`](fn.extract_bits.html). 28 | pub trait ExtractBits { 29 | #[inline] 30 | fn extract_bits(self, U, U) -> Self; 31 | } 32 | 33 | impl ExtractBits for T { 34 | #[inline] 35 | fn extract_bits(self, start: U, length: U) -> Self { 36 | extract_bits(self, start, length) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/word/flip_bit.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Flip the `bit` of `x`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1011_0010u8; 15 | /// assert_eq!(flip_bit(n, 7u8), 0b0011_0010u8); 16 | /// assert_eq!(n.flip_bit(6u8), 0b1111_0010u8); 17 | /// assert_eq!(n.flip_bit(5u8), 0b1001_0010u8); 18 | /// ``` 19 | #[inline] 20 | pub fn flip_bit(x: T, bit: U) -> T { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x ^ (T::one() << bit.to()) 23 | } 24 | 25 | /// Method version of [`flip_bit`](fn.flip_bit.html). 26 | pub trait FlipBit { 27 | #[inline] 28 | fn flip_bit(self, n: U) -> Self; 29 | } 30 | 31 | impl FlipBit for T { 32 | #[inline] 33 | fn flip_bit(self, n: U) -> Self { 34 | flip_bit(self, n) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/flip_bits_geq.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Flips all bits of `x` at position >= `bit`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1001_0010u8; 15 | /// let s = 0b0111_0010u8; 16 | /// assert_eq!(n.flip_bits_geq(5u8), s); 17 | /// assert_eq!(flip_bits_geq(n, 5u8), s); 18 | /// ``` 19 | #[inline] 20 | pub fn flip_bits_geq(x: T, bit: U) -> T { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x ^ !((T::one() << bit.to()) - T::one()) 23 | 24 | } 25 | 26 | /// Method version of [`flip_bits_geq`](fn.flip_bits_geq.html). 27 | pub trait FlipBitsGeq { 28 | #[inline] 29 | fn flip_bits_geq(self, n: U) -> Self; 30 | } 31 | 32 | impl FlipBitsGeq for T { 33 | #[inline] 34 | fn flip_bits_geq(self, n: U) -> Self { 35 | flip_bits_geq(self, n) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/word/flip_bits_leq.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Flips all bits of `x` at position <= `bit`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1011_0010u8; 15 | /// let s = 0b1000_1101u8; 16 | /// assert_eq!(n.flip_bits_leq(5u8), s); 17 | /// assert_eq!(flip_bits_leq(n, 5u8), s); 18 | /// ``` 19 | #[inline] 20 | pub fn flip_bits_leq(x: T, bit: U) -> T { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x ^ ((T::one() << (T::one() + bit.to())) - T::one()) 23 | } 24 | 25 | /// Method version of [`flip_bits_leq`](fn.flip_bits_leq.html). 26 | pub trait FlipBitsLeq { 27 | #[inline] 28 | fn flip_bits_leq(self, n: U) -> Self; 29 | } 30 | 31 | impl FlipBitsLeq for T { 32 | #[inline] 33 | fn flip_bits_leq(self, n: U) -> Self { 34 | flip_bits_leq(self, n) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/floor_pow2.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Round `x` to the previous power of 2. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `x <= 0`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// assert_eq!(2.floor_pow2(), 2); 15 | /// assert_eq!(floor_pow2(3), 2); 16 | /// assert_eq!(4.floor_pow2(), 4); 17 | /// assert_eq!(5.floor_pow2(), 4); 18 | /// assert_eq!(6.floor_pow2(), 4); 19 | /// assert_eq!(7.floor_pow2(), 4); 20 | /// assert_eq!(8.floor_pow2(), 8); 21 | /// ``` 22 | #[inline] 23 | pub fn floor_pow2(x: T) -> T { 24 | debug_assert!(x > T::zero()); 25 | let mut x = x; 26 | let s = T::byte_size(); 27 | x = x | (x >> T::one()); 28 | x = x | (x >> T::from_u8(2)); 29 | x = x | (x >> T::from_u8(4)); 30 | if s > T::one() { 31 | x = x | (x >> T::from_u8(8)); 32 | if s > T::from_u8(2) { 33 | x = x | (x >> T::from_u8(16)); 34 | if s > T::from_u8(4) { 35 | x = x | (x >> T::from_u8(32)); 36 | } 37 | } 38 | } 39 | x - (x >> T::one()) 40 | } 41 | 42 | /// Method version of [`floor_pow2`](fn.floor_pow2.html). 43 | pub trait FloorPow2 { 44 | #[inline] 45 | fn floor_pow2(self) -> Self; 46 | } 47 | 48 | impl FloorPow2 for T { 49 | #[inline] 50 | fn floor_pow2(self) -> Self { 51 | floor_pow2(self) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/word/from_be.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Convert integer from big endian to the target's endianness. 4 | /// 5 | /// On big endian this is a no-op. On little endian the bytes are swapped. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use bitwise::word::*; 11 | /// 12 | /// let n = 0x0123456789ABCDEFu64; 13 | /// 14 | /// if cfg!(target_endian = "big") { 15 | /// assert_eq!(n.from_be(), n); 16 | /// assert_eq!(from_be(n), n); 17 | /// } else { 18 | /// assert_eq!(n.from_be(), n.swap_bytes()); 19 | /// assert_eq!(from_be(n), n.swap_bytes()); 20 | /// } 21 | /// ``` 22 | #[inline] 23 | pub fn from_be(x: T) -> T { 24 | T::from_be(x) 25 | } 26 | -------------------------------------------------------------------------------- /src/word/from_le.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Convert integer from little endian to the target's endianness. 4 | /// 5 | /// On little endian this is a no-op. On big endian the bytes are swapped. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use bitwise::word::*; 11 | /// 12 | /// let n = 0x0123456789ABCDEFu64; 13 | /// 14 | /// if cfg!(target_endian = "little") { 15 | /// assert_eq!(from_le(n), n); 16 | /// assert_eq!(n.from_le(), n); 17 | /// } else { 18 | /// assert_eq!(from_le(n), n.swap_bytes()); 19 | /// assert_eq!(n.from_le(), n.swap_bytes()); 20 | /// } 21 | /// ``` 22 | #[inline] 23 | pub fn from_le(x: T) -> T { 24 | T::from_le(x) 25 | } 26 | -------------------------------------------------------------------------------- /src/word/gcd.rs: -------------------------------------------------------------------------------- 1 | //! Greatest Common Divisor algorithms that use bit manipulation. 2 | //! 3 | //! Note: this is not intended to provide _the_ fastest GCD implementation 4 | //! possible, but only to provide those algorithms that are implemented using 5 | //! bit manipulation. 6 | //! 7 | //! A fast GCD implementation will probably want to switch algorithms depending 8 | //! on the size of the input, and will involve other algorithms like Lehmer's 9 | //! and probably parallelization. The `benches/gcd.rs` benchmarks might be 10 | //! useful for making these decisions. 11 | 12 | use word::Word; 13 | 14 | pub mod test_util { 15 | use super::Word; 16 | 17 | pub fn invariant(x: T, y: T, gcd: T) -> bool { 18 | if x == T::zero() { 19 | gcd == y 20 | } else if y == T::zero() { 21 | gcd == x 22 | } else { 23 | x % gcd == T::zero() && y % gcd == T::zero() 24 | } 25 | } 26 | 27 | 28 | pub fn run_u8 u8>(from: u8, to: u8, f: F) { 29 | (from..to) 30 | .map(|x| { 31 | let xs: [u8; 1] = [x]; 32 | (from..to) 33 | .zip(xs.iter().cycle()) 34 | .map(|(x, &y)| { 35 | let gcd = f(x, y); 36 | assert!(invariant(x, y, gcd)) 37 | }) 38 | .count(); 39 | }) 40 | .count(); 41 | } 42 | 43 | pub fn run_u16 u16>(from: u16, to: u16, f: F) { 44 | (from..to) 45 | .map(|x| { 46 | let xs: [u16; 1] = [x]; 47 | (from..to) 48 | .zip(xs.iter().cycle()) 49 | .map(|(x, &y)| { 50 | let gcd = f(x, y); 51 | assert!(invariant(x, y, gcd)) 52 | }) 53 | .count(); 54 | }) 55 | .count(); 56 | } 57 | 58 | 59 | } 60 | 61 | #[cfg(test)] 62 | mod tests { 63 | use super::*; 64 | #[test] 65 | fn test_u8() { 66 | test_util::run_u8(0, u8::max_value(), euclid::recursive); 67 | test_util::run_u8(0, u8::max_value(), euclid::iterative); 68 | test_util::run_u8(0, u8::max_value(), steins::recursive); 69 | test_util::run_u8(0, u8::max_value(), steins::iterative); 70 | test_util::run_u8(0, u8::max_value(), steins::iterative_xor); 71 | } 72 | 73 | } 74 | 75 | pub mod euclid { 76 | //! Recursive implementation of the GCD algorithm. 77 | use word::Word; 78 | 79 | #[inline] 80 | pub fn recursive(x: T, y: T) -> T { 81 | if y == T::zero() { 82 | x 83 | } else { 84 | recursive(y, x % y) 85 | } 86 | } 87 | 88 | #[inline] 89 | pub fn iterative(x: T, y: T) -> T { 90 | let mut x = x; 91 | let mut y = y; 92 | while y != T::zero() { 93 | let t = y; 94 | y = x % y; 95 | x = t; 96 | } 97 | x 98 | } 99 | } 100 | 101 | pub mod steins { 102 | use std; 103 | use word::{Word, IsEven, IsOdd}; 104 | #[inline] pub fn recursive(x: T, y: T) -> T { 105 | match (x, y) { 106 | (x, y) if (x == y) => x, 107 | (x, y) if (x == T::zero()) => y, 108 | (x, y) if (y == T::zero()) => x, 109 | (x, y) => { 110 | match (x.is_odd(), y.is_odd()) { 111 | (false, false) => recursive(x >> T::one(), y >> T::one()) << T::one(), 112 | (false, true) => recursive(x >> T::one(), y), 113 | (true, false) => recursive(x, y >> T::one()), 114 | (true, true) => { 115 | if x >= y { 116 | recursive((x - y) >> T::one(), x) 117 | } else { 118 | recursive((y - x) >> T::one(), x) 119 | } 120 | } 121 | } 122 | } 123 | 124 | } 125 | } 126 | 127 | #[inline]pub fn iterative(x: T, y: T) -> T { 128 | if x == T::zero() { return y; } 129 | if y == T::zero() { return x; } 130 | 131 | let mut x = x; 132 | let mut y = y; 133 | let mut shift = T::zero(); 134 | while (x | y).is_even() { 135 | x = x >> T::one(); 136 | y = y >> T::one(); 137 | shift = shift + T::one(); 138 | } 139 | 140 | while x.is_even() { 141 | x = x >> T::one(); 142 | } 143 | 144 | 145 | loop { 146 | while y.is_even() { 147 | y = y >> T::one(); 148 | } 149 | 150 | if x > y { 151 | std::mem::swap(&mut x, &mut y); 152 | } 153 | y = y - x; 154 | 155 | if y == T::zero() { break; } 156 | 157 | } 158 | x << shift 159 | } 160 | 161 | 162 | #[inline]pub fn iterative_xor(x: T, y: T) -> T { 163 | let mut x = x; 164 | let mut y = y; 165 | while y != T::zero() { 166 | x = x % y; 167 | y = y ^ x; 168 | x = x ^ y; 169 | y = y ^ x; 170 | } 171 | x 172 | } 173 | } 174 | 175 | /* 176 | 177 | 178 | /// Greatest Common Divisor (GCD) of `x` and `y`. 179 | /// 180 | /// 181 | /// # Keywords: 182 | /// 183 | /// Greatest Common Divisor, GCD. 184 | /// 185 | /// # Examples 186 | /// 187 | /// ``` 188 | /// use bitwise::word::*; 189 | /// 190 | /// ``` 191 | #[inline] 192 | pub fn greatest_common_divisor(x: T, y: T) -> T { 193 | 194 | } 195 | 196 | /// Method version of [`greatest_common_divisor`](fn.greatest_common_divisor.html). 197 | pub trait GCD { 198 | #[inline] 199 | fn greatest_common_divisor(self, Self) -> Self; 200 | } 201 | 202 | impl GCD for T { 203 | #[inline] 204 | fn greatest_common_divisor(self, y: Self) -> Self { 205 | greatest_common_divisor(self, y) 206 | } 207 | } 208 | */ 209 | -------------------------------------------------------------------------------- /src/word/greatest_common_divisor.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnzlbg/bitwise/c2e35a9fb32c04f3a121c9466edf9c2c9c6dad58/src/word/greatest_common_divisor.rs -------------------------------------------------------------------------------- /src/word/hamming_distance.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Hamming distance between the binary representation of `x` and `y`. 4 | /// 5 | /// The Hamming distance is the minimum number of bits that one needs to change 6 | /// in `x` to make it equal to `y`. 7 | /// 8 | /// # Keywords: 9 | /// 10 | /// Hamming distance. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// let n = 0b_1011_0111u8; 18 | /// 19 | /// // distance of 1: 20 | /// let d1a = 0b_1111_0111u8; 21 | /// let d1b = 0b_1011_0101u8; 22 | /// 23 | /// // distance of 2: 24 | /// let d2a = 0b_1111_1111u8; 25 | /// let d2b = 0b_1010_0101u8; 26 | /// 27 | /// // distance of 3: 28 | /// let d3a = 0b_1111_1110u8; 29 | /// let d3b = 0b_0010_0101u8; 30 | /// 31 | /// assert_eq!(hamming_distance(n, d1a), 1); 32 | /// assert_eq!(hamming_distance(n, d1b), 1); 33 | /// assert_eq!(hamming_distance(n, d2a), 2); 34 | /// assert_eq!(hamming_distance(n, d2b), 2); 35 | /// assert_eq!(hamming_distance(n, d3a), 3); 36 | /// assert_eq!(hamming_distance(n, d3b), 3); 37 | /// ``` 38 | #[inline] 39 | pub fn hamming_distance(x: T, y: T) -> T { 40 | (x ^ y).popcnt() 41 | } 42 | 43 | /// Method version of [`hamming_distance`](fn.hamming_distance.html). 44 | pub trait HammingDistance { 45 | #[inline] 46 | fn hamming_distance(self, Self) -> Self; 47 | } 48 | 49 | impl HammingDistance for T { 50 | #[inline] 51 | fn hamming_distance(self, y: Self) -> Self { 52 | hamming_distance(self, y) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/word/inner_perfect_shuffle.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ReverseBitGroups, OuterPerfectShuffle}; 2 | 3 | /// Inner Perfect Shuffle of `x`. 4 | /// 5 | /// See also: 6 | /// [Hacker's Delight: shuffling bits](http://icodeguru.com/Embedded/Hacker's-Delight/047.htm). 7 | /// 8 | /// # Examples 9 | /// 10 | /// ``` 11 | /// use bitwise::word::*; 12 | /// 13 | /// let n = 0b0110_0101_1101_1011_1111_1001_0110_0011u32; 14 | /// // abcd efgh ijkl mnop ABCD EFGH IJKL MNOP, 15 | /// let s = 0b1011_1110_1001_0011_0111_1001_0100_1111u32; 16 | /// // AaBb CcDd EeFf GgHh IiJj KkLl MmNn OoPp 17 | /// 18 | /// assert_eq!(n.inner_perfect_shuffle(), s); 19 | /// assert_eq!(inner_perfect_shuffle(n), s); 20 | /// ``` 21 | #[inline] 22 | pub fn inner_perfect_shuffle(x: T) -> T { 23 | let hwb = T::bit_size().to_u8() / 2u8; 24 | x.reverse_bit_groups(hwb, 1u8).outer_perfect_shuffle() 25 | } 26 | 27 | /// Method version of [`inner_perfect_shuffle`](fn.inner_perfect_shuffle.html). 28 | pub trait InnerPerfectShuffle { 29 | #[inline] 30 | fn inner_perfect_shuffle(self) -> Self; 31 | } 32 | 33 | impl InnerPerfectShuffle for T { 34 | #[inline] 35 | fn inner_perfect_shuffle(self) -> Self { 36 | inner_perfect_shuffle(self) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/word/inner_perfect_unshuffle.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ReverseBitGroups, OuterPerfectUnshuffle}; 2 | 3 | /// Inner Perfect Unshuffle of `x`. 4 | /// 5 | /// See also: 6 | /// [Hacker's Delight: shuffling bits](http://icodeguru.com/Embedded/Hacker's-Delight/047.htm). 7 | /// 8 | /// # Examples 9 | /// 10 | /// ``` 11 | /// use bitwise::word::*; 12 | /// 13 | /// let n = 0b1011_1110_1001_0011_0111_1001_0100_1111u32; 14 | /// // AaBb CcDd EeFf GgHh IiJj KkLl MmNn OoPp 15 | /// let s = 0b0110_0101_1101_1011_1111_1001_0110_0011u32; 16 | /// // abcd efgh ijkl mnop ABCD EFGH IJKL MNOP, 17 | /// 18 | /// assert_eq!(n.inner_perfect_unshuffle(), s); 19 | /// assert_eq!(inner_perfect_unshuffle(n), s); 20 | /// ``` 21 | #[inline] 22 | pub fn inner_perfect_unshuffle(x: T) -> T { 23 | let hwb = T::bit_size().to_u8() / 2u8; 24 | x.outer_perfect_unshuffle().reverse_bit_groups(hwb, 1u8) 25 | } 26 | 27 | /// Method version of [`inner_perfect_unshuffle`](fn.inner_perfect_unshuffle.html). 28 | pub trait InnerPerfectUnshuffle { 29 | #[inline] 30 | fn inner_perfect_unshuffle(self) -> Self; 31 | } 32 | 33 | impl InnerPerfectUnshuffle for T { 34 | #[inline] 35 | fn inner_perfect_unshuffle(self) -> Self { 36 | inner_perfect_unshuffle(self) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/word/is_aligned.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, UnsignedWord, ToWord}; 2 | 3 | /// Is `x` aligned to `alignment` bytes. 4 | /// 5 | /// Returns true if `x == 0` or `x` is a multiple of `alignment`, where 6 | /// `alignment >= 1`. 7 | /// 8 | /// # Panics 9 | /// 10 | /// If `alignment < 1`. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// assert!(2.is_aligned(1u8)); 18 | /// assert!(is_aligned(2, 2u8)); 19 | /// assert!(!2.is_aligned(4u8)); 20 | /// assert!(!2.is_aligned(8u8)); 21 | /// 22 | /// assert!(3.is_aligned(1u8)); 23 | /// assert!(!3.is_aligned(2u8)); 24 | /// assert!(!3.is_aligned(4u8)); 25 | /// assert!(!3.is_aligned(8u8)); 26 | /// 27 | /// assert!(4.is_aligned(1u8)); 28 | /// assert!(4.is_aligned(2u8)); 29 | /// assert!(4.is_aligned(4u8)); 30 | /// assert!(!4.is_aligned(8u8)); 31 | /// ``` 32 | #[inline] 33 | pub fn is_aligned(x: T, alignment: U) -> bool { 34 | debug_assert!(U::one() <= alignment); 35 | (x & (alignment - U::one()).to()) == T::zero() 36 | } 37 | 38 | /// Method version of [`is_aligned`](fn.is_aligned.html). 39 | pub trait IsAligned { 40 | #[inline] 41 | fn is_aligned(self, U) -> bool; 42 | } 43 | 44 | impl IsAligned for T { 45 | #[inline] 46 | fn is_aligned(self, u: U) -> bool { 47 | is_aligned(self, u) 48 | } 49 | } 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | use word::*; 54 | use quickcheck::{TestResult, QuickCheck}; 55 | 56 | macro_rules! prop_is_aligned_tests { 57 | ($($name:ident: ($WordType:ty, $UnsignedType:ty),)*) => { 58 | $( 59 | #[test] 60 | fn $name() { 61 | fn inner(x: $WordType, alignment: $UnsignedType) -> TestResult { 62 | if alignment < 1 { 63 | return TestResult::discard(); 64 | } 65 | if !alignment.is_pow2() { 66 | return TestResult::discard(); 67 | } 68 | 69 | let res = x.is_aligned(alignment); 70 | 71 | if x == 0 || (x % alignment) == 0 { // zero or multiple 72 | TestResult::from_bool(res) 73 | } else { 74 | TestResult::from_bool(!res) 75 | } 76 | } 77 | QuickCheck::new().quickcheck(inner as fn($WordType, $UnsignedType) -> TestResult); 78 | } 79 | )* 80 | } 81 | } 82 | 83 | prop_is_aligned_tests! { 84 | prop_is_aligned_u8_u8: (u8, u8), 85 | prop_is_aligned_u16_u16: (u16, u16), 86 | prop_is_aligned_u32_u32: (u32, u32), 87 | prop_is_aligned_u64_u64: (u64, u64), 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/word/is_even.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Is `x` even. 4 | /// 5 | /// # Examples 6 | /// 7 | /// ``` 8 | /// use bitwise::word::*; 9 | /// 10 | /// assert!(0.is_even()); 11 | /// assert!(!1.is_even()); 12 | /// assert!(is_even(2)); 13 | /// assert!(!3.is_even()); 14 | /// assert!(4.is_even()); 15 | /// ``` 16 | #[inline] 17 | pub fn is_even(x: T) -> bool { 18 | !x & T::one() == T::one() 19 | } 20 | 21 | /// Method version of [`is_even`](fn.is_even.html). 22 | pub trait IsEven { 23 | #[inline] 24 | fn is_even(self) -> bool; 25 | } 26 | 27 | impl IsEven for T { 28 | #[inline] 29 | fn is_even(self) -> bool { 30 | is_even(self) 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | use word::*; 37 | use quickcheck::{TestResult, QuickCheck}; 38 | 39 | macro_rules! prop_is_even_tests { 40 | ($($name:ident: $WordType:ty,)*) => { 41 | $( 42 | #[test] 43 | fn $name() { 44 | fn inner(x: $WordType) -> TestResult { 45 | let rem = (x % 2) == 0; 46 | let res = x.is_even(); 47 | TestResult::from_bool(rem == res) 48 | } 49 | QuickCheck::new().quickcheck(inner as fn($WordType) -> TestResult); 50 | } 51 | )* 52 | } 53 | } 54 | 55 | prop_is_even_tests! { 56 | prop_is_even_u8: u8, 57 | prop_is_even_i8: i8, 58 | prop_is_even_u16: u16, 59 | prop_is_even_i16: i16, 60 | prop_is_even_u32: u32, 61 | prop_is_even_i32: i32, 62 | prop_is_even_u64: u64, 63 | prop_is_even_i64: i64, 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/word/is_odd.rs: -------------------------------------------------------------------------------- 1 | use word::{Word}; 2 | 3 | /// Is `x` odd. 4 | /// 5 | /// # Examples 6 | /// 7 | /// ``` 8 | /// use bitwise::word::*; 9 | /// 10 | /// assert!(!0.is_odd()); 11 | /// assert!(1.is_odd()); 12 | /// assert!(!is_odd(2)); 13 | /// assert!(3.is_odd()); 14 | /// assert!(!4.is_odd()); 15 | /// ``` 16 | #[inline] 17 | pub fn is_odd(x: T) -> bool { 18 | x & T::one() == T::one() 19 | } 20 | 21 | /// Method version of [`is_odd`](fn.is_odd.html). 22 | pub trait IsOdd { 23 | #[inline] 24 | fn is_odd(self) -> bool; 25 | } 26 | 27 | impl IsOdd for T { 28 | #[inline] 29 | fn is_odd(self) -> bool { 30 | is_odd(self) 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | use word::*; 37 | use quickcheck::{TestResult, QuickCheck}; 38 | 39 | macro_rules! prop_is_odd_tests { 40 | ($($name:ident: $WordType:ty,)*) => { 41 | $( 42 | #[test] 43 | fn $name() { 44 | fn inner(x: $WordType) -> TestResult { 45 | let rem = (x % 2) != 0; 46 | let res = x.is_odd(); 47 | TestResult::from_bool(rem == res) 48 | } 49 | QuickCheck::new().quickcheck(inner as fn($WordType) -> TestResult); 50 | } 51 | )* 52 | } 53 | } 54 | 55 | prop_is_odd_tests! { 56 | prop_is_odd_u8: u8, 57 | prop_is_odd_i8: i8, 58 | prop_is_odd_u16: u16, 59 | prop_is_odd_i16: i16, 60 | prop_is_odd_u32: u32, 61 | prop_is_odd_i32: i32, 62 | prop_is_odd_u64: u64, 63 | prop_is_odd_i64: i64, 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/word/is_pow2.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Is `x` a power of 2. 4 | /// 5 | /// # Examples 6 | /// 7 | /// ``` 8 | /// use bitwise::word::*; 9 | /// 10 | /// assert!(!0.is_pow2()); 11 | /// assert!(2.is_pow2()); 12 | /// assert!(!is_pow2(3)); 13 | /// assert!(4.is_pow2()); 14 | /// assert!(!5.is_pow2()); 15 | /// assert!(!6.is_pow2()); 16 | /// assert!(!7.is_pow2()); 17 | /// assert!(8.is_pow2()); 18 | /// ``` 19 | #[inline] 20 | pub fn is_pow2(x: T) -> bool { 21 | x > T::zero() && ((x & (x - T::one())) == T::zero()) 22 | } 23 | 24 | /// Method version of [`is_pow2`](fn.is_pow2.html). 25 | pub trait IsPow2 { 26 | #[inline] 27 | fn is_pow2(self) -> bool; 28 | } 29 | 30 | impl IsPow2 for T { 31 | #[inline] 32 | fn is_pow2(self) -> bool { 33 | is_pow2(self) 34 | } 35 | } 36 | 37 | #[cfg(test)] 38 | mod tests { 39 | use word::*; 40 | use quickcheck::{TestResult, QuickCheck}; 41 | 42 | macro_rules! prop_is_pow2_tests { 43 | ($($name:ident: $WordType:ty,)*) => { 44 | $( 45 | #[test] 46 | fn $name() { 47 | fn inner(x: $WordType) -> TestResult { 48 | if x <= 0 { 49 | return TestResult::discard(); 50 | } 51 | 52 | // Determine if y is a power of two in the 53 | // keep-dividing-until-we-hit-the-floor method. 54 | let mut y = x; 55 | while ((y % 2) == 0) && y > 1 { 56 | y /= 2; 57 | } 58 | 59 | let rem = y == 1; 60 | let res = x.is_pow2(); 61 | TestResult::from_bool(rem == res) 62 | } 63 | QuickCheck::new().quickcheck(inner as fn($WordType) -> TestResult); 64 | } 65 | )* 66 | } 67 | } 68 | 69 | prop_is_pow2_tests! { 70 | prop_is_pow2_u8: u8, 71 | prop_is_pow2_i8: i8, 72 | prop_is_pow2_u16: u16, 73 | prop_is_pow2_i16: i16, 74 | prop_is_pow2_u32: u32, 75 | prop_is_pow2_i32: i32, 76 | prop_is_pow2_u64: u64, 77 | prop_is_pow2_i64: i64, 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/word/isolate_least_significant_one.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Returns mask with the least significant set bit of `x` set to 1. 4 | /// 5 | /// If `x` is 0 returns 0. 6 | /// 7 | /// # Intrinsics: 8 | /// - BMI 1.0: blsi. 9 | /// - TBM: blsic, not. 10 | /// 11 | /// # Examples 12 | /// 13 | /// ``` 14 | /// use bitwise::word::*; 15 | /// 16 | /// let n = 0b0110; 17 | /// let s = 0b0010; 18 | /// 19 | /// assert_eq!(n.isolate_least_significant_one(), s); 20 | /// assert_eq!(isolate_least_significant_one(0), 0); 21 | /// ``` 22 | #[inline] 23 | pub fn isolate_least_significant_one(x: T) -> T { 24 | x.blsi() 25 | } 26 | 27 | /// Method version of [`isolate_least_significant_one`](fn.isolate_least_significant_one.html). 28 | pub trait IsolateLeastSignificantOne { 29 | #[inline] 30 | fn isolate_least_significant_one(self) -> Self; 31 | } 32 | 33 | impl IsolateLeastSignificantOne for T { 34 | #[inline] 35 | fn isolate_least_significant_one(self) -> Self { 36 | isolate_least_significant_one(self) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/word/isolate_least_significant_zero.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Returns mask with the least significant zero bit of `x` set to 1. 4 | /// 5 | /// All other bits of the mask are set to zero. If `x` contains only set bits, 6 | /// returns 0. 7 | /// 8 | /// # Intrinsics: 9 | /// - TBM: blcic (or: blci, not). 10 | /// 11 | /// # Examples 12 | /// 13 | /// ``` 14 | /// use bitwise::word::*; 15 | /// 16 | /// let n = 0b0101; 17 | /// let s = 0b0010; 18 | /// 19 | /// assert_eq!(n.isolate_least_significant_zero(), s); 20 | /// assert_eq!(isolate_least_significant_zero(0b1111_1111u8), 0u8); 21 | /// ``` 22 | #[inline] 23 | pub fn isolate_least_significant_zero(x: T) -> T { 24 | x.blcic() 25 | } 26 | 27 | /// Method version of [`isolate_least_significant_zero`](fn.isolate_least_significant_zero.html). 28 | pub trait IsolateLeastSignificantZero { 29 | #[inline] 30 | fn isolate_least_significant_zero(self) -> Self; 31 | } 32 | 33 | impl IsolateLeastSignificantZero for T { 34 | #[inline] 35 | fn isolate_least_significant_zero(self) -> Self { 36 | isolate_least_significant_zero(self) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/word/mask_trailing_ones.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Returns mask with the trailing 1's of `self` set. 4 | /// 5 | /// If `x` is zero, returns `0`. 6 | /// 7 | /// # Intrinsics: 8 | /// - TBM: t1mskc, not. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// use bitwise::word::*; 14 | /// 15 | /// assert_eq!(0b0101_1111u8.mask_trailing_ones(), 0b0001_1111u8); 16 | /// assert_eq!(mask_trailing_ones(0), 0); 17 | /// ``` 18 | #[inline] 19 | pub fn mask_trailing_ones(x: T) -> T { 20 | !x.t1mskc() 21 | } 22 | 23 | /// Method version of [`mask_trailing_ones`](fn.mask_trailing_ones.html). 24 | pub trait MaskTrailingOnes { 25 | #[inline] 26 | fn mask_trailing_ones(self) -> Self; 27 | } 28 | 29 | impl MaskTrailingOnes for T { 30 | #[inline] 31 | fn mask_trailing_ones(self) -> Self { 32 | mask_trailing_ones(self) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/word/mask_trailing_ones_and_least_significant_zero.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Returns mask with all trailing 1's of `x` and the least 4 | /// significant 0 bit set. 5 | /// 6 | /// # Intrinsics: 7 | /// - TBM: blcmsk. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b0101_1111u8; 15 | /// let s = 0b0011_1111u8; 16 | /// 17 | /// assert_eq!(n.mask_trailing_ones_and_least_significant_zero(), s); 18 | /// assert_eq!(mask_trailing_ones_and_least_significant_zero(n), s); 19 | /// ``` 20 | #[inline] 21 | pub fn mask_trailing_ones_and_least_significant_zero(x: T) -> T { 22 | x.blcmsk() 23 | } 24 | 25 | /// Method version of [`mask_trailing_zeros_and_least_significant_zero`](fn.mask_trailing_zeros_and_least_significant_zero.html). 26 | pub trait MaskTrailingOnesAndLeastSignificantZero { 27 | #[inline] 28 | fn mask_trailing_ones_and_least_significant_zero(self) -> Self; 29 | } 30 | 31 | impl MaskTrailingOnesAndLeastSignificantZero for T { 32 | #[inline] 33 | fn mask_trailing_ones_and_least_significant_zero(self) -> Self { 34 | mask_trailing_ones_and_least_significant_zero(self) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/mask_trailing_zeros.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Returns mask with the trailing 0's of `x` set. 4 | /// 5 | /// If all bits of `x` are set, returns `0`. 6 | /// 7 | /// # Intrinsics: 8 | /// - TBM: tzmsk. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// use bitwise::word::*; 14 | /// 15 | /// assert_eq!(0b0110_0000u8.mask_trailing_zeros(), 0b0001_1111u8); 16 | /// assert_eq!(mask_trailing_zeros(0b1111_1111u8), 0); 17 | /// ``` 18 | #[inline] 19 | pub fn mask_trailing_zeros(x: T) -> T { 20 | x.tzmsk() 21 | } 22 | 23 | /// Method version of [`mask_trailing_zeros`](fn.mask_trailing_zeros.html). 24 | pub trait MaskTrailingZeros { 25 | #[inline] 26 | fn mask_trailing_zeros(self) -> Self; 27 | } 28 | 29 | impl MaskTrailingZeros for T { 30 | #[inline] 31 | fn mask_trailing_zeros(self) -> Self { 32 | mask_trailing_zeros(self) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/word/mask_trailing_zeros_and_least_significant_one.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Returns mask with all of the trailing 0's of `x` and the least 4 | /// significant 1 bit set. 5 | /// 6 | /// # Intrinsics: 7 | /// - BMI: blsmsk. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b0101_0000u8; 15 | /// let s = 0b0001_1111u8; 16 | /// 17 | /// assert_eq!(n.mask_trailing_zeros_and_least_significant_one(), s); 18 | /// assert_eq!(mask_trailing_zeros_and_least_significant_one(n), s); 19 | /// ``` 20 | #[inline] 21 | pub fn mask_trailing_zeros_and_least_significant_one(x: T) -> T { 22 | x.blsmsk() 23 | } 24 | 25 | /// Method version of [`mask_trailing_zeros_and_least_significant_one`](fn.mask_trailing_zeros_and_least_significant_one.html). 26 | pub trait MaskTrailingZerosAndLeastSignificantOne { 27 | #[inline] 28 | fn mask_trailing_zeros_and_least_significant_one(self) -> Self; 29 | } 30 | 31 | impl MaskTrailingZerosAndLeastSignificantOne for T { 32 | #[inline] 33 | fn mask_trailing_zeros_and_least_significant_one(self) -> Self { 34 | mask_trailing_zeros_and_least_significant_one(self) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/mod.rs: -------------------------------------------------------------------------------- 1 | //! Algorithms for single words (u8...u64). 2 | 3 | mod word; 4 | pub use self::word::*; 5 | 6 | mod to_word; 7 | pub use self::to_word::*; 8 | 9 | mod count_zeros; 10 | pub use self::count_zeros::*; 11 | 12 | mod count_ones; 13 | pub use self::count_ones::*; 14 | 15 | mod count_leading_zeros; 16 | pub use self::count_leading_zeros::*; 17 | 18 | mod count_leading_ones; 19 | pub use self::count_leading_ones::*; 20 | 21 | mod count_trailing_zeros; 22 | pub use self::count_trailing_zeros::*; 23 | 24 | mod count_trailing_ones; 25 | pub use self::count_trailing_ones::*; 26 | 27 | mod shift_logical_left; 28 | pub use self::shift_logical_left::*; 29 | 30 | mod shift_logical_right; 31 | pub use self::shift_logical_right::*; 32 | 33 | mod shift_arithmetic_left; 34 | pub use self::shift_arithmetic_left::*; 35 | 36 | mod shift_arithmetic_right; 37 | pub use self::shift_arithmetic_right::*; 38 | 39 | mod rotate_left; 40 | pub use self::rotate_left::*; 41 | 42 | mod rotate_right; 43 | pub use self::rotate_right::*; 44 | 45 | mod swap_bytes; 46 | pub use self::swap_bytes::*; 47 | 48 | mod from_be; 49 | pub use self::from_be::*; 50 | 51 | mod from_le; 52 | pub use self::from_le::*; 53 | 54 | mod to_be; 55 | pub use self::to_be::*; 56 | 57 | mod to_le; 58 | pub use self::to_le::*; 59 | 60 | mod pow; 61 | pub use self::pow::*; 62 | 63 | mod parity; 64 | pub use self::parity::*; 65 | 66 | mod clear_least_significant_one; 67 | pub use self::clear_least_significant_one::*; 68 | 69 | mod set_least_significant_zero; 70 | pub use self::set_least_significant_zero::*; 71 | 72 | mod isolate_least_significant_one; 73 | pub use self::isolate_least_significant_one::*; 74 | 75 | mod isolate_least_significant_zero; 76 | pub use self::isolate_least_significant_zero::*; 77 | 78 | mod clear_trailing_ones; 79 | pub use self::clear_trailing_ones::*; 80 | 81 | mod set_trailing_zeros; 82 | pub use self::set_trailing_zeros::*; 83 | 84 | mod mask_trailing_zeros; 85 | pub use self::mask_trailing_zeros::*; 86 | 87 | mod mask_trailing_ones; 88 | pub use self::mask_trailing_ones::*; 89 | 90 | mod mask_trailing_zeros_and_least_significant_one; 91 | pub use self::mask_trailing_zeros_and_least_significant_one::*; 92 | 93 | mod mask_trailing_ones_and_least_significant_zero; 94 | pub use self::mask_trailing_ones_and_least_significant_zero::*; 95 | 96 | mod set_bit; 97 | pub use self::set_bit::*; 98 | 99 | mod clear_bit; 100 | pub use self::clear_bit::*; 101 | 102 | mod flip_bit; 103 | pub use self::flip_bit::*; 104 | 105 | mod test_bit; 106 | pub use self::test_bit::*; 107 | 108 | mod copy_bit; 109 | pub use self::copy_bit::*; 110 | 111 | mod reverse_bit_groups; 112 | pub use self::reverse_bit_groups::*; 113 | 114 | mod reverse_bits; 115 | pub use self::reverse_bits::*; 116 | 117 | mod reverse_bit_pairs; 118 | pub use self::reverse_bit_pairs::*; 119 | 120 | mod reverse_bit_nibbles; 121 | pub use self::reverse_bit_nibbles::*; 122 | 123 | mod reverse_byte_groups; 124 | pub use self::reverse_byte_groups::*; 125 | 126 | mod reverse_bytes; 127 | pub use self::reverse_bytes::*; 128 | 129 | mod clear_bits_geq; 130 | pub use self::clear_bits_geq::*; 131 | 132 | mod clear_bits_leq; 133 | pub use self::clear_bits_leq::*; 134 | 135 | mod set_bits_geq; 136 | pub use self::set_bits_geq::*; 137 | 138 | mod set_bits_leq; 139 | pub use self::set_bits_leq::*; 140 | 141 | mod flip_bits_geq; 142 | pub use self::flip_bits_geq::*; 143 | 144 | mod flip_bits_leq; 145 | pub use self::flip_bits_leq::*; 146 | 147 | mod is_pow2; 148 | pub use self::is_pow2::*; 149 | 150 | mod ceil_pow2; 151 | pub use self::ceil_pow2::*; 152 | 153 | mod floor_pow2; 154 | pub use self::floor_pow2::*; 155 | 156 | mod is_aligned; 157 | pub use self::is_aligned::*; 158 | 159 | mod align_up; 160 | pub use self::align_up::*; 161 | 162 | mod align_down; 163 | pub use self::align_down::*; 164 | 165 | mod outer_perfect_shuffle; 166 | pub use self::outer_perfect_shuffle::*; 167 | 168 | mod outer_perfect_unshuffle; 169 | pub use self::outer_perfect_unshuffle::*; 170 | 171 | mod inner_perfect_shuffle; 172 | pub use self::inner_perfect_shuffle::*; 173 | 174 | mod inner_perfect_unshuffle; 175 | pub use self::inner_perfect_unshuffle::*; 176 | 177 | mod parallel_bits_deposit; 178 | pub use self::parallel_bits_deposit::*; 179 | 180 | mod parallel_bits_extract; 181 | pub use self::parallel_bits_extract::*; 182 | 183 | mod extract_bits; 184 | pub use self::extract_bits::*; 185 | 186 | mod hamming_distance; 187 | pub use self::hamming_distance::*; 188 | 189 | mod is_even; 190 | pub use self::is_even::*; 191 | 192 | mod is_odd; 193 | pub use self::is_odd::*; 194 | 195 | pub mod gcd; 196 | 197 | pub mod morton; 198 | pub use morton::decode_2d as morton_decode_2d; 199 | pub use morton::decode_3d as morton_decode_3d; 200 | pub use morton::encode_2d as morton_encode_2d; 201 | pub use morton::encode_3d as morton_encode_3d; 202 | -------------------------------------------------------------------------------- /src/word/morton.rs: -------------------------------------------------------------------------------- 1 | //! Encoding/decoding of Morton Z-curve indices. 2 | //! 3 | //! The encode/decode 2d/3d functions in this module expose the fastest 4 | //! algorithm for the target and set of target features enabled when a nightly 5 | //! compiler is used. 6 | //! 7 | //! ## Correctness 8 | //! 9 | //! The default implementation is loss-less, that is, it preserve all 10 | //! information when encoding/decoding. This means that the encoding/decoding 11 | //! functions are invertible: `encode(decode(m)) == m`). 12 | //! 13 | //! The `bitmask` and `lut` implementations in the sub-modules are _lossy_ (not 14 | //! loss-less). 15 | //! 16 | //! The `decode/encode_3d_high_bits` functions can be used to wrap a lossy 17 | //! implementation into a loss-less one. 18 | //! 19 | //! ## Performance of the default algorithm 20 | //! 21 | //! The default implementation is loss-less. It uses the `bitmask`-based 22 | //! everywhere except on x86 targets that support the BMI 2.0 instruction set. 23 | //! 24 | //! ### Choice of default algorithms 25 | //! 26 | //! This decision was based on the following facts: 27 | //! 28 | //! - The `bmi2` algorithm is the fastest on machines with the BMI 2.0 29 | //! instruction set, but very slow otherwise. 30 | //! - The performance of the `bitmask` and the look-up table (`lut`) algorithms in 31 | //! the micro-benchmarks is comparable. 32 | //! - The `lut` version requires more memory than the `bitmask` version. 33 | //! 34 | //! and this hypothesis: 35 | //! 36 | //! The `bitmask` version might deliver better performance on real applications 37 | //! than the `lut` version because it uses less cache. 38 | //! 39 | //! Since every real application is different, all implementations are still 40 | //! provided in the sub-modules. So when in doubt, benchmark your application 41 | //! with the different implementations and make an informed choice. 42 | //! 43 | //! ### Choice of loss-less by default 44 | //! 45 | //! The cost of making a lossy algorithm `loss-less` is within the measurement 46 | //! error. The trend shows a positive cost, but this cost is negligible, and 47 | //! the correctness/reliability gains are worth it. 48 | //! 49 | //! Still, the higher bits that get lost by the lossy implementations are 50 | //! probably completely irrelevant in practice unless one is dealing with 51 | //! insanely large z-Curves. 52 | //! 53 | //! Negligibly faster lossy implementations are provided in the `bitmask` and 54 | //! `lut` sub-modules. 55 | //! 56 | //! The `bmi2` implementation is always loss-less. 57 | 58 | #![allow(dead_code)] 59 | 60 | use word; 61 | use word::Word; 62 | 63 | pub mod lut { 64 | //! Encoding/decoding of Morton Z-curve indices using a look-up table. 65 | 66 | use word::{Word, ToWord}; 67 | 68 | const ENCODE_2D: [u16; 256] = 69 | [0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84, 85, 256, 257, 260, 261, 272, 273, 70 | 276, 277, 320, 321, 324, 325, 336, 337, 340, 341, 1024, 1025, 1028, 1029, 1040, 1041, 71 | 1044, 1045, 1088, 1089, 1092, 1093, 1104, 1105, 1108, 1109, 1280, 1281, 1284, 1285, 1296, 72 | 1297, 1300, 1301, 1344, 1345, 1348, 1349, 1360, 1361, 1364, 1365, 4096, 4097, 4100, 4101, 73 | 4112, 4113, 4116, 4117, 4160, 4161, 4164, 4165, 4176, 4177, 4180, 4181, 4352, 4353, 4356, 74 | 4357, 4368, 4369, 4372, 4373, 4416, 4417, 4420, 4421, 4432, 4433, 4436, 4437, 5120, 5121, 75 | 5124, 5125, 5136, 5137, 5140, 5141, 5184, 5185, 5188, 5189, 5200, 5201, 5204, 5205, 5376, 76 | 5377, 5380, 5381, 5392, 5393, 5396, 5397, 5440, 5441, 5444, 5445, 5456, 5457, 5460, 5461, 77 | 16384, 16385, 16388, 16389, 16400, 16401, 16404, 16405, 16448, 16449, 16452, 16453, 78 | 16464, 16465, 16468, 16469, 16640, 16641, 16644, 16645, 16656, 16657, 16660, 16661, 79 | 16704, 16705, 16708, 16709, 16720, 16721, 16724, 16725, 17408, 17409, 17412, 17413, 80 | 17424, 17425, 17428, 17429, 17472, 17473, 17476, 17477, 17488, 17489, 17492, 17493, 81 | 17664, 17665, 17668, 17669, 17680, 17681, 17684, 17685, 17728, 17729, 17732, 17733, 82 | 17744, 17745, 17748, 17749, 20480, 20481, 20484, 20485, 20496, 20497, 20500, 20501, 83 | 20544, 20545, 20548, 20549, 20560, 20561, 20564, 20565, 20736, 20737, 20740, 20741, 84 | 20752, 20753, 20756, 20757, 20800, 20801, 20804, 20805, 20816, 20817, 20820, 20821, 85 | 21504, 21505, 21508, 21509, 21520, 21521, 21524, 21525, 21568, 21569, 21572, 21573, 86 | 21584, 21585, 21588, 21589, 21760, 21761, 21764, 21765, 21776, 21777, 21780, 21781, 87 | 21824, 21825, 21828, 21829, 21840, 21841, 21844, 21845]; 88 | 89 | const DECODE_2D: [u8; 256] = 90 | [0, 1, 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 4, 5, 4, 5, 6, 7, 91 | 6, 7, 0, 1, 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 4, 5, 4, 5, 92 | 6, 7, 6, 7, 8, 9, 8, 9, 10, 11, 10, 11, 8, 9, 8, 9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 93 | 15, 14, 15, 12, 13, 12, 13, 14, 15, 14, 15, 8, 9, 8, 9, 10, 11, 10, 11, 8, 9, 8, 9, 10, 94 | 11, 10, 11, 12, 13, 12, 13, 14, 15, 14, 15, 12, 13, 12, 13, 14, 15, 14, 15, 0, 1, 0, 1, 95 | 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 4, 5, 4, 5, 6, 7, 6, 7, 0, 1, 96 | 0, 1, 2, 3, 2, 3, 0, 1, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 4, 5, 4, 5, 6, 7, 6, 7, 97 | 8, 9, 8, 9, 10, 11, 10, 11, 8, 9, 8, 9, 10, 11, 10, 11, 12, 13, 12, 13, 14, 15, 14, 15, 98 | 12, 13, 12, 13, 14, 15, 14, 15, 8, 9, 8, 9, 10, 11, 10, 11, 8, 9, 8, 9, 10, 11, 10, 11, 99 | 12, 13, 12, 13, 14, 15, 14, 15, 12, 13, 12, 13, 14, 15, 14, 15]; 100 | 101 | const ENCODE_3D: [u32; 256] = 102 | [0x00000000, 0x00000001, 0x00000008, 0x00000009, 0x00000040, 0x00000041, 0x00000048, 103 | 0x00000049, 0x00000200, 0x00000201, 0x00000208, 0x00000209, 0x00000240, 0x00000241, 104 | 0x00000248, 0x00000249, 0x00001000, 0x00001001, 0x00001008, 0x00001009, 0x00001040, 105 | 0x00001041, 0x00001048, 0x00001049, 0x00001200, 0x00001201, 0x00001208, 0x00001209, 106 | 0x00001240, 0x00001241, 0x00001248, 0x00001249, 0x00008000, 0x00008001, 0x00008008, 107 | 0x00008009, 0x00008040, 0x00008041, 0x00008048, 0x00008049, 0x00008200, 0x00008201, 108 | 0x00008208, 0x00008209, 0x00008240, 0x00008241, 0x00008248, 0x00008249, 0x00009000, 109 | 0x00009001, 0x00009008, 0x00009009, 0x00009040, 0x00009041, 0x00009048, 0x00009049, 110 | 0x00009200, 0x00009201, 0x00009208, 0x00009209, 0x00009240, 0x00009241, 0x00009248, 111 | 0x00009249, 0x00040000, 0x00040001, 0x00040008, 0x00040009, 0x00040040, 0x00040041, 112 | 0x00040048, 0x00040049, 0x00040200, 0x00040201, 0x00040208, 0x00040209, 0x00040240, 113 | 0x00040241, 0x00040248, 0x00040249, 0x00041000, 0x00041001, 0x00041008, 0x00041009, 114 | 0x00041040, 0x00041041, 0x00041048, 0x00041049, 0x00041200, 0x00041201, 0x00041208, 115 | 0x00041209, 0x00041240, 0x00041241, 0x00041248, 0x00041249, 0x00048000, 0x00048001, 116 | 0x00048008, 0x00048009, 0x00048040, 0x00048041, 0x00048048, 0x00048049, 0x00048200, 117 | 0x00048201, 0x00048208, 0x00048209, 0x00048240, 0x00048241, 0x00048248, 0x00048249, 118 | 0x00049000, 0x00049001, 0x00049008, 0x00049009, 0x00049040, 0x00049041, 0x00049048, 119 | 0x00049049, 0x00049200, 0x00049201, 0x00049208, 0x00049209, 0x00049240, 0x00049241, 120 | 0x00049248, 0x00049249, 0x00200000, 0x00200001, 0x00200008, 0x00200009, 0x00200040, 121 | 0x00200041, 0x00200048, 0x00200049, 0x00200200, 0x00200201, 0x00200208, 0x00200209, 122 | 0x00200240, 0x00200241, 0x00200248, 0x00200249, 0x00201000, 0x00201001, 0x00201008, 123 | 0x00201009, 0x00201040, 0x00201041, 0x00201048, 0x00201049, 0x00201200, 0x00201201, 124 | 0x00201208, 0x00201209, 0x00201240, 0x00201241, 0x00201248, 0x00201249, 0x00208000, 125 | 0x00208001, 0x00208008, 0x00208009, 0x00208040, 0x00208041, 0x00208048, 0x00208049, 126 | 0x00208200, 0x00208201, 0x00208208, 0x00208209, 0x00208240, 0x00208241, 0x00208248, 127 | 0x00208249, 0x00209000, 0x00209001, 0x00209008, 0x00209009, 0x00209040, 0x00209041, 128 | 0x00209048, 0x00209049, 0x00209200, 0x00209201, 0x00209208, 0x00209209, 0x00209240, 129 | 0x00209241, 0x00209248, 0x00209249, 0x00240000, 0x00240001, 0x00240008, 0x00240009, 130 | 0x00240040, 0x00240041, 0x00240048, 0x00240049, 0x00240200, 0x00240201, 0x00240208, 131 | 0x00240209, 0x00240240, 0x00240241, 0x00240248, 0x00240249, 0x00241000, 0x00241001, 132 | 0x00241008, 0x00241009, 0x00241040, 0x00241041, 0x00241048, 0x00241049, 0x00241200, 133 | 0x00241201, 0x00241208, 0x00241209, 0x00241240, 0x00241241, 0x00241248, 0x00241249, 134 | 0x00248000, 0x00248001, 0x00248008, 0x00248009, 0x00248040, 0x00248041, 0x00248048, 135 | 0x00248049, 0x00248200, 0x00248201, 0x00248208, 0x00248209, 0x00248240, 0x00248241, 136 | 0x00248248, 0x00248249, 0x00249000, 0x00249001, 0x00249008, 0x00249009, 0x00249040, 137 | 0x00249041, 0x00249048, 0x00249049, 0x00249200, 0x00249201, 0x00249208, 0x00249209, 138 | 0x00249240, 0x00249241, 0x00249248, 0x00249249]; 139 | 140 | const DECODE_3D: [u8; 512] = 141 | [0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 142 | 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 143 | 2, 3, 2, 3, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 144 | 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 145 | 6, 7, 6, 7, 6, 7, 6, 7, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 0, 1, 146 | 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 147 | 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 4, 5, 148 | 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 149 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 150 | 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 151 | 2, 3, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 152 | 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 153 | 6, 7, 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 0, 1, 0, 1, 0, 1, 154 | 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 155 | 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 4, 5, 156 | 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 157 | 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 158 | 6, 7]; 159 | 160 | #[inline] 161 | pub fn encode_2d(x: Coordinate, 162 | y: Coordinate) 163 | -> MortonIndex { 164 | let mut result = MortonIndex::zero(); 165 | const MASK: u8 = 0x000000FF; 166 | let mask = Coordinate::from_u8(MASK); 167 | for i in (1..Coordinate::byte_size().to_u8() + 1).rev() { 168 | let shift = Coordinate::from_u8((i - 1) * 8); 169 | let y_index = ((y >> shift) & mask).to_u8() as usize; 170 | let x_index = ((x >> shift) & mask).to_u8() as usize; 171 | result = result.wrapping_shl(MortonIndex::from_u8(16)) | 172 | (ENCODE_2D[y_index] << 1).to() | 173 | (ENCODE_2D[x_index]).to(); 174 | } 175 | result 176 | } 177 | 178 | #[inline] 179 | fn decode_2d_h(v: MortonIndex, 180 | lut: &[u8], 181 | startshift: u8) 182 | -> Coordinate { 183 | let mut result = MortonIndex::zero(); 184 | const MASK: u8 = 0x000000FF; 185 | let mask = MortonIndex::from_u8(MASK); 186 | let loops = MortonIndex::byte_size().to_u8(); 187 | for i in 0..loops { 188 | let shift = (i * 8) + startshift; 189 | let index: usize = ((v >> shift.to()) & mask.to()).to_usize(); 190 | let val = MortonIndex::from_u8(lut[index]); 191 | result = result | (val << (4 * i as u32).to()).to(); 192 | } 193 | result.to() 194 | } 195 | 196 | #[inline] 197 | pub fn decode_2d(v: MortonIndex) 198 | -> (Coordinate, Coordinate) { 199 | (decode_2d_h(v, &DECODE_2D, 0), decode_2d_h(v, &DECODE_2D, 1)) 200 | } 201 | 202 | #[inline] 203 | pub fn encode_3d(x: Coordinate, 204 | y: Coordinate, 205 | z: Coordinate) 206 | -> MortonIndex { 207 | let mut result = MortonIndex::zero(); 208 | const MASK: u8 = 0x000000FF; 209 | let mask = Coordinate::from_u8(MASK); 210 | for i in (1..Coordinate::byte_size().to_u8() + 1).rev() { 211 | let shift = Coordinate::from_u8((i - 1) * 8); 212 | let y_index = ((y >> shift) & mask).to_u8() as usize; 213 | let x_index = ((x >> shift) & mask).to_u8() as usize; 214 | let z_index = ((z >> shift) & mask).to_u8() as usize; 215 | result = result.wrapping_shl(MortonIndex::from_u8(24)) | 216 | (ENCODE_3D[z_index] << 2).to() | 217 | (ENCODE_3D[y_index] << 1).to() | 218 | (ENCODE_3D[x_index]).to(); 219 | } 220 | result 221 | } 222 | 223 | #[inline] 224 | fn decode_3d_h(v: MortonIndex, 225 | lut: &[u8], 226 | startshift: u8) 227 | -> Coordinate { 228 | let mut result = MortonIndex::zero(); 229 | const MASK: u16 = 0x000001ff; // TODO: try u8 230 | let mask = MortonIndex::from_u16(MASK); 231 | let loops = MortonIndex::byte_size().to_u8(); 232 | let loops = if loops >= 8 { 7 } else { loops }; 233 | for i in 0..loops { 234 | let shift = (i * 9) + startshift; 235 | let index: usize = ((v >> shift.to()) & mask).to_usize(); 236 | let val = MortonIndex::from_u8(lut[index]); 237 | result = result | (val << (3 * i as u32).to()).to(); 238 | } 239 | result.to() 240 | } 241 | 242 | 243 | #[inline] 244 | pub fn decode_3d 245 | (v: MortonIndex) 246 | -> (Coordinate, Coordinate, Coordinate) { 247 | (decode_3d_h(v, &DECODE_3D, 0), 248 | decode_3d_h(v, &DECODE_3D, 1), 249 | decode_3d_h(v, &DECODE_3D, 2)) 250 | } 251 | } 252 | 253 | pub mod bmi2 { 254 | //! Encoding/decoding of Morton Z-curve indices using BMI2 pdep/pext instructions. 255 | use word::{Word, ToWord, ParallelBitsDeposit, ParallelBitsExtract}; 256 | 257 | #[inline] 258 | pub fn encode_2d(x: Coordinate, 259 | y: Coordinate) 260 | -> MortonIndex { 261 | (y.parallel_bits_deposit(0xAAAAAAAAAAAAAAAAu64) | 262 | x.parallel_bits_deposit(0x5555555555555555u64)) 263 | .to() 264 | } 265 | 266 | #[inline] 267 | pub fn encode_3d(x: Coordinate, 268 | y: Coordinate, 269 | z: Coordinate) 270 | -> MortonIndex { 271 | (z.parallel_bits_deposit(0x4924924924924924u64) | 272 | y.parallel_bits_deposit(0x2492492492492492u64) | 273 | x.parallel_bits_deposit(0x9249249249249249u64)) 274 | .to() 275 | } 276 | 277 | #[inline] 278 | pub fn decode_2d(v: MortonIndex) 279 | -> (Coordinate, Coordinate) { 280 | (v.parallel_bits_extract(0x5555555555555555u64).to(), 281 | v.parallel_bits_extract(0xAAAAAAAAAAAAAAAAu64).to()) 282 | } 283 | 284 | 285 | #[inline] 286 | pub fn decode_3d 287 | (v: MortonIndex) 288 | -> (Coordinate, Coordinate, Coordinate) { 289 | (v.parallel_bits_extract(0x9249249249249249u64).to(), 290 | v.parallel_bits_extract(0x2492492492492492u64).to(), 291 | v.parallel_bits_extract(0x4924924924924924u64).to()) 292 | } 293 | } 294 | 295 | 296 | pub mod bitmask { 297 | //! Encoding/decoding of Morton Z-curve indices using precomputed bitmasks. 298 | use word::Word; 299 | 300 | const MASK_2D_U32: [u32; 6] = [0xFFFFFFFF, 0x0000FFFF, 0x00FF00FF, 0x0F0F0F0F, 0x33333333, 301 | 0x55555555]; 302 | const MASK_2D_U64: [u64; 6] = [0x00000000FFFFFFFF, 303 | 0x0000FFFF0000FFFF, 304 | 0x00FF00FF00FF00FF, 305 | 0x0F0F0F0F0F0F0F0F, 306 | 0x3333333333333333, 307 | 0x5555555555555555]; 308 | 309 | const MASK_3D_U32: [u32; 5] = [0x000003ff, 0x30000ff, 0x0300f00f, 0x30c30c3, 0x9249249]; 310 | const MASK_3D_U64: [u64; 6] = [0x1fffffu64, 311 | 0x1f00000000ffffu64, 312 | 0x1f0000ff0000ffu64, 313 | 0x100f00f00f00f00fu64, 314 | 0x10c30c30c30c30c3u64, 315 | 0x1249249249249249u64]; 316 | 317 | 318 | #[inline] 319 | fn split_by_second_bits(x: Coordinate) -> MortonIndex { 320 | match Coordinate::bit_size().to_u8() { 321 | 32 => { 322 | let mut x = x.to_u32(); 323 | x = (x | x << 16) & MASK_2D_U32[1]; 324 | x = (x | x << 8) & MASK_2D_U32[2]; 325 | x = (x | x << 4) & MASK_2D_U32[3]; 326 | x = (x | x << 2) & MASK_2D_U32[4]; 327 | x = (x | x << 1) & MASK_2D_U32[5]; 328 | MortonIndex::from_u32(x) 329 | } 330 | 64 => { 331 | let mut x = x.to_u64(); 332 | x = (x | x << 32) & MASK_2D_U64[0]; 333 | x = (x | x << 16) & MASK_2D_U64[1]; 334 | x = (x | x << 8) & MASK_2D_U64[2]; 335 | x = (x | x << 4) & MASK_2D_U64[3]; 336 | x = (x | x << 2) & MASK_2D_U64[4]; 337 | x = (x | x << 1) & MASK_2D_U64[5]; 338 | MortonIndex::from_u64(x) 339 | } 340 | _ => MortonIndex::from_u32(split_by_second_bits(x.to_u32())), 341 | } 342 | } 343 | 344 | #[inline] 345 | fn get_second_bits(x: MortonIndex) -> Coordinate { 346 | match MortonIndex::bit_size().to_u8() { 347 | 32 => { 348 | let mut x = x.to_u32(); 349 | x &= MASK_2D_U32[5]; 350 | x = (x ^ (x >> 1)) & MASK_2D_U32[4]; 351 | x = (x ^ (x >> 2)) & MASK_2D_U32[3]; 352 | x = (x ^ (x >> 4)) & MASK_2D_U32[2]; 353 | x = (x ^ (x >> 8)) & MASK_2D_U32[1]; 354 | x = (x ^ (x >> 16)) & MASK_2D_U32[0]; 355 | Coordinate::from_u32(x) 356 | } 357 | 64 => { 358 | let mut x = x.to_u64(); 359 | x &= MASK_2D_U64[5]; 360 | x = (x ^ (x >> 1)) & MASK_2D_U64[4]; 361 | x = (x ^ (x >> 2)) & MASK_2D_U64[3]; 362 | x = (x ^ (x >> 4)) & MASK_2D_U64[2]; 363 | x = (x ^ (x >> 8)) & MASK_2D_U64[1]; 364 | x = (x ^ (x >> 16)) & MASK_2D_U64[0]; 365 | Coordinate::from_u64(x) 366 | } 367 | _ => Coordinate::from_u32(get_second_bits(x.to_u32())), 368 | } 369 | } 370 | 371 | #[inline] 372 | pub fn encode_2d(x: Coordinate, 373 | y: Coordinate) 374 | -> MortonIndex { 375 | split_by_second_bits::(x) | 376 | (split_by_second_bits::(y) << MortonIndex::one()) 377 | } 378 | 379 | #[inline] 380 | pub fn decode_2d(v: MortonIndex) 381 | -> (Coordinate, Coordinate) { 382 | (get_second_bits(v), get_second_bits(v >> MortonIndex::one())) 383 | } 384 | 385 | #[inline] 386 | fn split_by_third_bits(x: Coordinate) -> MortonIndex { 387 | match Coordinate::bit_size().to_u8() { 388 | 32 => { 389 | let mut x = x.to_u32(); 390 | x &= MASK_3D_U32[0]; 391 | x = (x | x << 16) & MASK_3D_U32[1]; 392 | x = (x | x << 8) & MASK_3D_U32[2]; 393 | x = (x | x << 4) & MASK_3D_U32[3]; 394 | x = (x | x << 2) & MASK_3D_U32[4]; 395 | MortonIndex::from_u32(x) 396 | } 397 | 64 => { 398 | let mut x = x.to_u64() & MASK_3D_U64[0]; 399 | x = (x | x << 32) & MASK_3D_U64[1]; 400 | x = (x | x << 16) & MASK_3D_U64[2]; 401 | x = (x | x << 8) & MASK_3D_U64[3]; 402 | x = (x | x << 4) & MASK_3D_U64[4]; 403 | x = (x | x << 2) & MASK_3D_U64[5]; 404 | MortonIndex::from_u64(x) 405 | } 406 | _ => MortonIndex::from_u32(split_by_third_bits(x.to_u32())), 407 | } 408 | } 409 | 410 | #[inline] 411 | fn get_third_bits(x: MortonIndex) -> Coordinate { 412 | match MortonIndex::bit_size().to_u8() { 413 | 32 => { 414 | let mut x = x.to_u32(); 415 | x &= MASK_3D_U32[4]; 416 | x = (x ^ (x >> 2)) & MASK_3D_U32[3]; 417 | x = (x ^ (x >> 4)) & MASK_3D_U32[2]; 418 | x = (x ^ (x >> 8)) & MASK_3D_U32[1]; 419 | x = (x ^ (x >> 16)) & MASK_3D_U32[0]; 420 | Coordinate::from_u32(x) 421 | } 422 | 64 => { 423 | let mut x = x.to_u64() & MASK_3D_U64[5]; 424 | x = (x ^ (x >> 2)) & MASK_3D_U64[4]; 425 | x = (x ^ (x >> 4)) & MASK_3D_U64[3]; 426 | x = (x ^ (x >> 8)) & MASK_3D_U64[2]; 427 | x = (x ^ ((x) >> 16)) & MASK_3D_U64[1]; 428 | x = (x ^ ((x) >> 32)) & MASK_3D_U64[0]; 429 | Coordinate::from_u64(x) 430 | } 431 | 432 | _ => Coordinate::from_u32(get_third_bits(x.to_u32())), 433 | } 434 | } 435 | 436 | #[inline] 437 | pub fn encode_3d(x: Coordinate, 438 | y: Coordinate, 439 | z: Coordinate) 440 | -> MortonIndex { 441 | split_by_third_bits::(x) | 442 | (split_by_third_bits::(y) << MortonIndex::one()) | 443 | (split_by_third_bits::(z) << MortonIndex::from_u8(2)) 444 | } 445 | 446 | #[inline] 447 | pub fn decode_3d 448 | (v: MortonIndex) 449 | -> (Coordinate, Coordinate, Coordinate) { 450 | (get_third_bits(v), 451 | get_third_bits(v >> MortonIndex::one()), 452 | get_third_bits(v >> MortonIndex::from_u8(2))) 453 | } 454 | } 455 | 456 | /// Encode coordinates `x` and `y` into an interleaved Morton index for a 457 | /// z-Curve. 458 | /// 459 | /// Using `_.i` to denote the `i`-th bit in a word, given the `x` and `y` 460 | /// coordinates with the following bit patterns: 461 | /// 462 | /// `x: |x.M|...|x.1|x.0|` 463 | /// `y: |y.M|...|y.1|y.0|` 464 | /// 465 | /// where `M == T::bit_size()`, 466 | /// 467 | /// this function encodes the bits of `x` and `y` into a value `v` using the 468 | /// Morton z-Curve encoding: 469 | /// 470 | /// `v = |y.N|x.N|...|y.1|x.1|y.0|x.0|` 471 | /// 472 | /// where `N == T::bit_size() / 2`. 473 | /// 474 | /// # Example 475 | /// ``` 476 | /// use bitwise::word::morton; 477 | /// 478 | /// let x = 0b0000_1010u8; 479 | /// let y = 0b0000_0011u8; 480 | /// let r = 0b01_00_11_10u8; 481 | /// assert_eq!(morton::encode_2d(x, y), r); 482 | /// assert_eq!(morton::encode_2d(x as u32, y as u32), r as u32); 483 | /// assert_eq!(morton::encode_2d(x as u64, y as u64), r as u64); 484 | /// ``` 485 | #[inline] 486 | pub fn encode_2d(x: T, y: T) -> T { 487 | #[cfg(RUSTC_IS_NIGHTLY)] 488 | { 489 | if cfg!(target_feature = "bmi2") { 490 | bmi2::encode_2d(x, y) 491 | } else { 492 | // bitmask::encode_2d(x, y) 493 | lut::encode_2d(x, y) 494 | } 495 | } 496 | #[cfg(not(RUSTC_IS_NIGHTLY))] 497 | { 498 | // bitmask::encode_2d(x, y) 499 | lut::encode_2d(x, y) 500 | } 501 | } 502 | 503 | /// Encodes the high-bits of `x` and `y` into the Morton index `v`. 504 | #[inline] 505 | pub fn encode_3d_high_bits(v: T, x: T, y: T, _: T) -> T { 506 | let mut v = v; 507 | match T::bit_size().to_u8() { 508 | 32 => { 509 | v = word::copy_bit(x, 10u8, v, 30u8); 510 | v = word::copy_bit(y, 10u8, v, 31u8); 511 | } 512 | 64 => { 513 | v = word::copy_bit(x, 21u8, v, 63u8); 514 | } 515 | _ => {} 516 | }; 517 | v 518 | } 519 | 520 | /// Encode coordinates `x`, `y`, and `z` into an interleaved Morton index for a 521 | /// z-Curve. 522 | /// 523 | /// Using `_.i` to denote the `i`-th bit in a word, given the `x`, `y`, and `z` 524 | /// coordinates with the following bit patterns: 525 | /// 526 | /// `x: |x.M|...|x.1|x.0|` 527 | /// `y: |y.M|...|y.1|y.0|` 528 | /// `z: |z.M|...|z.1|z.0|` 529 | /// 530 | /// where `M == T::bit_size()`, 531 | /// 532 | /// this function encodes the bits of `x`, `y`, and `z` into a value `v` using 533 | /// the Morton z-Curve encoding: 534 | /// 535 | /// `v = |z.N|y.N|x.N|...|z.1|y.1|x.1|z.0|y.0|x.0|` 536 | /// 537 | /// where `N == T::bit_size() / 3`. 538 | /// 539 | /// Note: the encoded Morton index is always invertible to the coordinates using 540 | /// the `encode_3d` function. 541 | /// 542 | /// # Example 543 | /// ``` 544 | /// use bitwise::word::morton; 545 | /// 546 | /// let x = 0b0000_1010u8; 547 | /// let y = 0b0000_0011u8; 548 | /// let z = 0b0000_1110u8; 549 | /// let r = 0b00_111_010u8; 550 | /// let r32 = 0b101_100_111_010u32; 551 | /// assert_eq!(morton::encode_3d(x, y, z), r); 552 | /// assert_eq!(morton::encode_3d(x as u32, y as u32, z as u32), r32); 553 | /// ``` 554 | #[inline] 555 | pub fn encode_3d(x: T, y: T, z: T) -> T { 556 | #[cfg(RUSTC_IS_NIGHTLY)] 557 | { 558 | if cfg!(target_feature = "bmi2") { 559 | bmi2::encode_3d(x, y, z) 560 | } else { 561 | let v = bitmask::encode_3d(x, y, z); 562 | encode_3d_high_bits(v, x, y, z) 563 | } 564 | } 565 | #[cfg(not(RUSTC_IS_NIGHTLY))] 566 | { 567 | let v = bitmask::encode_3d(x, y, z); 568 | encode_3d_high_bits(v, x, y, z) 569 | } 570 | } 571 | 572 | /// Decodes an interleaved Morton index for a Z-Curve into two-dimensional 573 | /// coordinates. 574 | /// 575 | /// Using `_.i` to denote the `i`-th bit in a word, this function decodes 576 | /// the following bit pattern of `v`: 577 | /// 578 | /// `v = |y.N|x.N|...|y.1|x.1|y.0|x.0|` 579 | /// 580 | /// where `N == T::bit_size() / 2`, 581 | /// 582 | /// into the coordinates `x` and `y` with the following bit pattern: 583 | /// 584 | /// `x: |...0|x.N|...|x.1|x.0|` 585 | /// `y: |...0|y.N|...|y.1|y.0|` 586 | /// 587 | /// # Example 588 | /// ``` 589 | /// use bitwise::word::morton; 590 | /// 591 | /// let x = 0b0000_1010u8; 592 | /// let y = 0b0000_0011u8; 593 | /// let r = 0b01_00_11_10u8; 594 | /// assert_eq!(morton::decode_2d(r), (x, y)); 595 | /// ``` 596 | #[inline] 597 | pub fn decode_2d(v: T) -> (T, T) { 598 | #[cfg(RUSTC_IS_NIGHTLY)] 599 | { 600 | if cfg!(target_feature = "bmi2") { 601 | bmi2::decode_2d(v) 602 | } else { 603 | bitmask::decode_2d(v) 604 | //lut::decode_2d(v) 605 | } 606 | } 607 | #[cfg(not(RUSTC_IS_NIGHTLY))] 608 | { 609 | bitmask::decode_2d(v) 610 | //lut::decode_2d(v) 611 | } 612 | } 613 | 614 | /// Decodes the high-bits of `b` into the coordinates `x` and `y`. 615 | #[inline] 616 | pub fn decode_3d_high_bits(v: T, x: T, y: T, z: T) -> (T, T, T) { 617 | let mut x = x; 618 | let mut y = y; 619 | match T::bit_size().to_u8() { 620 | 32 => { 621 | x = word::copy_bit(v, 30u8, x, 10u8); 622 | y = word::copy_bit(v, 31u8, y, 10u8); 623 | } 624 | 64 => { 625 | x = word::copy_bit(v, 63u8, x, 21u8); 626 | } 627 | _ => {} 628 | }; 629 | (x, y, z) 630 | } 631 | 632 | /// Decodes an interleaved Morton index for a Z-Curve into three-dimensional 633 | /// coordinates. 634 | /// 635 | /// Using `_.i` to denote the `i`-th bit in a word, this function decodes 636 | /// the following bit pattern of `v`: 637 | /// 638 | /// `v = |z.N|y.N|x.N|...|z.1|y.1|x.1|z.0|y.0|x.0|` 639 | /// 640 | /// where `N == T::bit_size() / 3`, 641 | /// 642 | /// into the coordinates `x`, `y`, and `z` with the following bit pattern: 643 | /// 644 | /// `x: ...|x.N|...|x.1|x.0|` 645 | /// `y: ...|y.N|...|y.1|y.0|` 646 | /// `y: ...|y.N|...|y.1|y.0|` 647 | /// 648 | /// Note: the decoded coordinates are always invertible to the morton code using 649 | /// the `decode_3d` function. 650 | /// 651 | /// # Example 652 | /// ``` 653 | /// use bitwise::word::morton; 654 | /// 655 | /// let x = 0b0000_0010u8; 656 | /// let y = 0b0000_0011u8; 657 | /// let z = 0b0000_0010u8; 658 | /// let r = 0b00_111_010u8; 659 | /// assert_eq!(morton::decode_3d(r), (x, y, z)); 660 | /// ``` 661 | #[inline] 662 | pub fn decode_3d(v: T) -> (T, T, T) { 663 | #[cfg(RUSTC_IS_NIGHTLY)] 664 | { 665 | if cfg!(target_feature = "bmi2") { 666 | bmi2::decode_3d(v) 667 | } else { 668 | let (x, y, z) = bitmask::decode_3d(v); 669 | decode_3d_high_bits(v, x, y, z) 670 | } 671 | } 672 | #[cfg(not(RUSTC_IS_NIGHTLY))] 673 | { 674 | let (x, y, z) = bitmask::decode_3d(v); 675 | decode_3d_high_bits(v, x, y, z) 676 | } 677 | } 678 | 679 | 680 | #[doc(hidden)] 681 | pub mod testing_utils { 682 | //! Testing utilities, used in tests and benchmarks (TODO: make optional) 683 | use super::*; 684 | use std::fmt::Debug; 685 | 686 | pub trait RunnerFn { 687 | fn run(&self, T); 688 | } 689 | 690 | pub struct Runner; 691 | impl Runner { 692 | pub fn run_u8(i: &T) { 693 | (0u8..u8::max_value()).map(|v| i.run(v)).count(); 694 | } 695 | pub fn run_u16(i: &T) { 696 | (0u16..u16::max_value()).map(|v| i.run(v)).count(); 697 | } 698 | pub fn run_u32(i: &T) { 699 | let t0_min = u16::max_value() as u32; 700 | let t0_max = t0_min + 1000000; 701 | (t0_min..t0_max).map(|v| i.run(v)).count(); 702 | let t1_max = u32::max_value(); 703 | let t1_min = t1_max - 1000000; 704 | (t1_min..t1_max).map(|v| i.run(v)).count(); 705 | } 706 | 707 | pub fn run_u64(i: &T) { 708 | let t0_min = u32::max_value() as u64; 709 | let t0_max = t0_min + 1000000; 710 | (t0_min..t0_max).map(|v| i.run(v)).count(); 711 | let t1_max = u64::max_value(); 712 | let t1_min = t1_max - 1000000; 713 | (t1_min..t1_max).map(|v| i.run(v)).count(); 714 | 715 | } 716 | 717 | pub fn run(i: T) { 718 | Runner::run_u8(&i); 719 | Runner::run_u16(&i); 720 | Runner::run_u32(&i); 721 | Runner::run_u64(&i); 722 | } 723 | } 724 | } 725 | 726 | #[cfg(test)] 727 | mod tests { 728 | use super::*; 729 | use super::testing_utils::*; 730 | use std::fmt::Debug; 731 | 732 | struct BMI2Invariant; 733 | 734 | impl RunnerFn for BMI2Invariant { 735 | fn run(&self, v: T) { 736 | { 737 | // 2D: 738 | let (x, y) = bmi2::decode_2d::(v); 739 | let vs = bmi2::encode_2d::(x, y); 740 | assert_eq!(vs, v); 741 | } 742 | { 743 | // 3D: 744 | let (x, y, z) = bmi2::decode_3d::(v); 745 | let vs = bmi2::encode_3d::(x, y, z); 746 | assert_eq!(vs, v); 747 | } 748 | } 749 | } 750 | 751 | #[test] 752 | fn bmi2_invariant() { 753 | Runner::run(BMI2Invariant {}); 754 | } 755 | 756 | struct BitmaskInvariant; 757 | 758 | impl RunnerFn for BitmaskInvariant { 759 | fn run(&self, v: T) { 760 | { 761 | // 2D: 762 | let (x, y) = bitmask::decode_2d::(v); 763 | let vs = bitmask::encode_2d::(x, y); 764 | let (x2, y2) = bitmask::decode_2d::(vs); 765 | let vs3 = bitmask::encode_2d::(x2, y2); 766 | assert_eq!(vs3, vs); 767 | } 768 | { 769 | let (x, y, z) = bitmask::decode_3d::(v); 770 | let vs = bitmask::encode_3d::(x, y, z); 771 | let (x2, y2, z2) = bitmask::decode_3d::(vs); 772 | let vs3 = bitmask::encode_3d::(x2, y2, z2); 773 | assert_eq!(vs3, vs); 774 | } 775 | 776 | } 777 | } 778 | 779 | 780 | #[test] 781 | fn bitmask_invariant() { 782 | Runner::run(BitmaskInvariant {}); 783 | } 784 | 785 | struct LUTInvariant; 786 | 787 | impl RunnerFn for LUTInvariant { 788 | fn run(&self, v: T) { 789 | { 790 | // 2D: 791 | let (x, y) = lut::decode_2d::(v); 792 | let vs = lut::encode_2d::(x, y); 793 | let (x2, y2) = lut::decode_2d::(vs); 794 | let vs3 = lut::encode_2d::(x2, y2); 795 | assert_eq!(vs3, vs); 796 | } 797 | { 798 | let (x, y, z) = lut::decode_3d::(v); 799 | let vs = lut::encode_3d::(x, y, z); 800 | let (x2, y2, z2) = lut::decode_3d::(vs); 801 | let vs3 = lut::encode_3d::(x2, y2, z2); 802 | assert_eq!(vs3, vs); 803 | } 804 | } 805 | } 806 | 807 | #[test] 808 | fn lut_invariant() { 809 | Runner::run(LUTInvariant {}); 810 | } 811 | 812 | struct CmpImpls; 813 | 814 | impl RunnerFn for CmpImpls { 815 | fn run(&self, v: T) { 816 | use word::clear_bits_geq::ClearBitsGeq; 817 | { 818 | // 2D: 819 | let (x_bmi2, y_bmi2) = bmi2::decode_2d::(v); 820 | 821 | let (x_m, y_m) = decode_2d::(v); 822 | assert_eq!(x_bmi2, x_m); 823 | assert_eq!(y_bmi2, y_m); 824 | 825 | let v_bmi2: T = bmi2::encode_2d(x_bmi2, y_bmi2); 826 | assert_eq!(v_bmi2, v); 827 | 828 | let v_m: T = encode_2d(x_bmi2, y_bmi2); 829 | assert_eq!(v_m, v); 830 | 831 | let (x_mb, y_mb) = bitmask::decode_2d::(v); 832 | 833 | assert_eq!(x_bmi2, x_mb); 834 | assert_eq!(y_bmi2, y_mb); 835 | 836 | let v_mb = bitmask::encode_2d::(x_bmi2, y_bmi2); 837 | assert_eq!(v_mb, v); 838 | 839 | let (x_lut, y_lut) = lut::decode_2d(v); 840 | assert_eq!(x_bmi2, x_lut); 841 | assert_eq!(y_bmi2, y_lut); 842 | 843 | let v_lut: T = lut::encode_2d(x_bmi2, y_bmi2); 844 | assert_eq!(v_lut, v); 845 | } 846 | { 847 | // 3D 848 | 849 | { 850 | //bmi2 and the public impls are always invertible 851 | let (x_bmi2, y_bmi2, z_bmi2) = bmi2::decode_3d::(v); 852 | let (x_m, y_m, z_m) = decode_3d(v); 853 | 854 | assert_eq!(x_bmi2, x_m); 855 | assert_eq!(y_bmi2, y_m); 856 | assert_eq!(z_bmi2, z_m); 857 | 858 | let v_bmi2: T = bmi2::encode_3d(x_bmi2, y_bmi2, z_bmi2); 859 | assert_eq!(v_bmi2, v); 860 | 861 | let v_m: T = encode_3d(x_bmi2, y_bmi2, z_bmi2); 862 | assert_eq!(v_m, v); 863 | } 864 | 865 | // note: BMI2 and LUT/BITMASK produce different results for 3D 866 | // because the last 2bits of a 32bit word and the last bit of a 867 | // 64bit word are not preserved in the decoding (such that 868 | // re-encoding produces a different key than the original value) 869 | let v = match T::bit_size().to_u8() { 870 | 32 => v.clear_bits_geq(30u8), 871 | 64 => v.clear_bits_geq(63u8), 872 | _ => v, 873 | }; 874 | 875 | let (x_bmi2, y_bmi2, z_bmi2) = bmi2::decode_3d::(v); 876 | let (x_mb, y_mb, z_mb) = bitmask::decode_3d::(v); 877 | 878 | assert_eq!(x_bmi2, x_mb); 879 | assert_eq!(y_bmi2, y_mb); 880 | assert_eq!(z_bmi2, z_mb); 881 | 882 | let v_mb = bitmask::encode_3d::(x_bmi2, y_bmi2, z_bmi2); 883 | assert_eq!(v_mb, v); 884 | 885 | 886 | let (x_lut, y_lut, z_lut) = lut::decode_3d(v); 887 | assert_eq!(x_bmi2, x_lut); 888 | assert_eq!(y_bmi2, y_lut); 889 | assert_eq!(z_bmi2, z_lut); 890 | 891 | let v_lut: T = lut::encode_3d(x_bmi2, y_bmi2, z_bmi2); 892 | assert_eq!(v_lut, v); 893 | } 894 | 895 | } 896 | } 897 | 898 | #[test] 899 | fn cmp_impls() { 900 | Runner::run(CmpImpls {}); 901 | } 902 | } 903 | -------------------------------------------------------------------------------- /src/word/outer_perfect_shuffle.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Outer Perfect Shuffle of `x`. 4 | /// 5 | /// See also: 6 | /// [Hacker's Delight: shuffling bits](http://icodeguru.com/Embedded/Hacker's-Delight/047.htm). 7 | /// 8 | /// # Examples 9 | /// 10 | /// ``` 11 | /// use bitwise::word::*; 12 | /// 13 | /// let n = 0b0110_0101_1101_1011_1111_1001_0110_0011u32; 14 | /// // abcd efgh ijkl mnop ABCD EFGH IJKL MNOP, 15 | /// let s = 0b0111_1101_0110_0011_1011_0110_1000_1111u32; 16 | /// // aAbB cCdD eEfF gGhH iIjJ kKlL mMnN oOpP, 17 | /// 18 | /// assert_eq!(n.outer_perfect_shuffle(), s); 19 | /// assert_eq!(outer_perfect_shuffle(n), s); 20 | /// ``` 21 | #[inline] 22 | pub fn outer_perfect_shuffle(x: T) -> T { 23 | let mut x = x; 24 | let s = T::byte_size(); 25 | if s > T::from_u8(4) { 26 | let t = (x ^ (x >> T::from_u8(16))) & T::from_u64(0x00000000FFFF0000u64); 27 | x = x ^ t ^ (t << T::from_u8(16)); 28 | } 29 | if s > T::from_u8(2) { 30 | let t = (x ^ (x >> T::from_u8(8))) & T::from_u64(0x0000FF000000FF00u64); 31 | x = x ^ t ^ (t << T::from_u8(8)); 32 | } 33 | if s > T::one() { 34 | let t = (x ^ (x >> T::from_u8(4))) & T::from_u64(0x00F000F000F000F0u64); 35 | x = x ^ t ^ (t << T::from_u8(4)); 36 | } 37 | let t = (x ^ (x >> T::from_u8(2))) & T::from_u64(0x0C0C0C0C0C0C0C0Cu64); 38 | x = x ^ t ^ (t << T::from_u8(2)); 39 | let t = (x ^ (x >> T::one())) & T::from_u64(0x2222222222222222u64); 40 | x = x ^ t ^ (t << T::one()); 41 | x 42 | } 43 | 44 | /// Method version of [`outer_perfect_shuffle`](fn.outer_perfect_shuffle.html). 45 | pub trait OuterPerfectShuffle { 46 | #[inline] 47 | fn outer_perfect_shuffle(self) -> Self; 48 | } 49 | 50 | impl OuterPerfectShuffle for T { 51 | #[inline] 52 | fn outer_perfect_shuffle(self) -> Self { 53 | outer_perfect_shuffle(self) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/word/outer_perfect_unshuffle.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Outer Perfect Unshuffle of `x`. 4 | /// 5 | /// See also: 6 | /// [Hacker's Delight: shuffling bits](http://icodeguru.com/Embedded/Hacker's-Delight/047.htm). 7 | /// 8 | /// # Examples 9 | /// 10 | /// ``` 11 | /// use bitwise::word::*; 12 | /// 13 | /// let n = 0b0111_1101_0110_0011_1011_0110_1000_1111u32; 14 | /// // aAbB cCdD eEfF gGhH iIjJ kKlL mMnN oOpP, 15 | /// let s = 0b0110_0101_1101_1011_1111_1001_0110_0011u32; 16 | /// // abcd efgh ijkl mnop ABCD EFGH IJKL MNOP, 17 | /// 18 | /// assert_eq!(n.outer_perfect_unshuffle(), s); 19 | /// assert_eq!(outer_perfect_unshuffle(n), s); 20 | /// ``` 21 | #[inline] 22 | pub fn outer_perfect_unshuffle(x: T) -> T { 23 | let mut x = x; 24 | let s = T::byte_size(); 25 | let t = (x ^ (x >> T::one())) & T::from_u64(0x2222222222222222u64); 26 | x = x ^ t ^ (t << T::one()); 27 | let t = (x ^ (x >> T::from_u8(2))) & T::from_u64(0x0C0C0C0C0C0C0C0Cu64); 28 | x = x ^ t ^ (t << T::from_u8(2)); 29 | if s > T::one() { 30 | let t = (x ^ (x >> T::from_u8(4))) & T::from_u64(0x00F000F000F000F0u64); 31 | x = x ^ t ^ (t << T::from_u8(4)); 32 | } 33 | if s > T::from_u8(2) { 34 | let t = (x ^ (x >> T::from_u8(8))) & T::from_u64(0x0000FF000000FF00u64); 35 | x = x ^ t ^ (t << T::from_u8(8)); 36 | } 37 | if s > T::from_u8(4) { 38 | let t = (x ^ (x >> T::from_u8(16))) & T::from_u64(0x00000000FFFF0000u64); 39 | x = x ^ t ^ (t << T::from_u8(16)); 40 | } 41 | x 42 | } 43 | 44 | /// Method version of [`outer_perfect_unshuffle`](fn.outer_perfect_unshuffle.html). 45 | pub trait OuterPerfectUnshuffle { 46 | #[inline] 47 | fn outer_perfect_unshuffle(self) -> Self; 48 | } 49 | 50 | impl OuterPerfectUnshuffle for T { 51 | #[inline] 52 | fn outer_perfect_unshuffle(self) -> Self { 53 | outer_perfect_unshuffle(self) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/word/parallel_bits_deposit.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord}; 2 | 3 | /// Parallel bits deposit of `mask` into `x`. 4 | /// 5 | /// # Keywords: 6 | /// 7 | /// Scatter. 8 | /// 9 | /// # Intrinsics: 10 | /// - BMI 2.0: pdep. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// let n = 0b1011_1110_1001_0011u16; 18 | /// 19 | /// let m0 = 0b0110_0011_1000_0101u16; 20 | /// let s0 = 0b0000_0010_0000_0101u16; 21 | /// 22 | /// let m1 = 0b1110_1011_1110_1111u16; 23 | /// let s1 = 0b1110_1001_0010_0011u16; 24 | /// 25 | /// assert_eq!(n.parallel_bits_deposit(m0), s0); 26 | /// assert_eq!(parallel_bits_deposit(n, m1), s1); 27 | /// ``` 28 | #[inline] 29 | pub fn parallel_bits_deposit(x: T, mask: U) -> T { 30 | x.pdep(mask.to()) 31 | } 32 | 33 | /// Method version of [`parallel_bits_deposit`](fn.parallel_bits_deposit.html). 34 | pub trait ParallelBitsDeposit { 35 | #[inline] 36 | fn parallel_bits_deposit(self, U) -> Self; 37 | } 38 | 39 | impl ParallelBitsDeposit for T { 40 | #[inline] 41 | fn parallel_bits_deposit(self, mask: U) -> Self { 42 | parallel_bits_deposit(self, mask) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/word/parallel_bits_extract.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord}; 2 | 3 | /// Parallel bits extract of `mask` from `x`. 4 | /// 5 | /// # Keywords: 6 | /// 7 | /// Gather. 8 | /// 9 | /// # Intrinsics: 10 | /// - BMI 2.0: pext. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// let n = 0b1011_1110_1001_0011u16; 18 | /// 19 | /// let m0 = 0b0110_0011_1000_0101u16; 20 | /// let s0 = 0b0000_0000_0011_0101u16; 21 | /// 22 | /// let m1 = 0b1110_1011_1110_1111u16; 23 | /// let s1 = 0b0001_0111_0100_0011u16; 24 | /// 25 | /// assert_eq!(n.parallel_bits_extract(m0), s0); 26 | /// assert_eq!(parallel_bits_extract(n, m1), s1); 27 | /// ``` 28 | #[inline] 29 | pub fn parallel_bits_extract(x: T, mask: U) -> T { 30 | x.pext(mask.to()) 31 | } 32 | 33 | /// Method version of [`parallel_bits_extract`](fn.parallel_bits_extract.html). 34 | pub trait ParallelBitsExtract { 35 | #[inline] 36 | fn parallel_bits_extract(self, U) -> Self; 37 | } 38 | 39 | impl ParallelBitsExtract for T { 40 | #[inline] 41 | fn parallel_bits_extract(self, mask: U) -> Self { 42 | parallel_bits_extract(self, mask) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/word/parity.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Number of set bits in `x` mod 2; i.e. 1 if the 4 | /// number of set bits in `x` is odd, zero otherwise 5 | /// 6 | /// # Intrinsics: 7 | /// -gcc/llvm: `__builtin_parity(x)`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n0 = 0b0000; // 0 -> even => parity = 0 15 | /// let n1 = 0b0001; // 1 -> odd => partiy = 1 16 | /// let n2 = 0b0010; // 1 -> odd => parity = 1 17 | /// let n3 = 0b0011; // 2 -> even => parity = 0 18 | /// 19 | /// assert_eq!(n0.parity(), 0); 20 | /// assert_eq!(n1.parity(), 1); 21 | /// assert_eq!(n2.parity(), 1); 22 | /// assert_eq!(n3.parity(), 0); 23 | /// assert_eq!(parity(n2), 1); 24 | /// ``` 25 | #[inline] 26 | pub fn parity(x: T) -> T { 27 | x.count_ones() & T::one() 28 | } 29 | 30 | /// Method version of [`parity`](fn.parity.html). 31 | pub trait Parity { 32 | #[inline] 33 | fn parity(self) -> Self; 34 | } 35 | 36 | impl Parity for T { 37 | #[inline] 38 | fn parity(self) -> Self { 39 | parity(self) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/word/pow.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Raises `x` to the power of `exp`. 4 | /// 5 | /// Uses exponentiation by squaring. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use bitwise::word::*; 11 | /// 12 | /// assert_eq!(pow(2i8, 6u8), 64i8); 13 | /// ``` 14 | #[inline] 15 | pub fn pow(x: T, exp: U) -> T { 16 | T::pow(x, exp.to()) 17 | } 18 | 19 | // TODO: figure out a way to offer the trait version without clashing with the 20 | // one in std: 21 | /* 22 | pub trait Pow { 23 | #[inline] fn pow(self, n: U) -> Self; 24 | } 25 | 26 | impl Pow for T { 27 | #[inline] fn pow(self, n: U) -> Self { 28 | pow(self, n) 29 | } 30 | } 31 | */ 32 | -------------------------------------------------------------------------------- /src/word/reverse_bit_groups.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, UnsignedWord, ToWord}; 2 | use word::is_pow2::*; 3 | 4 | /// Reverses groups of bits within each subword of `x`. 5 | /// 6 | /// * `group_bit_size` - The size (in bits) of the groups of bits to be 7 | /// reversed. 8 | /// * `no_subwords` - The number of subwords in `x`. 9 | /// 10 | /// The word `x` is divided into `no_subwords`. The bit groups of size 11 | /// `group_bit_size` are reversed within each subword. Bits within a bit group 12 | /// are _not_ reversed. 13 | /// 14 | /// The size in bits of a subword is thus `x::bit_size() / no_subword`. When 15 | /// `no_suboword == 1` the subword equals the original word. When 16 | /// `group_bit_size == 1` the single bits are reversed within a subword. 17 | /// 18 | /// Both `group_bit_size` and `no_subwords` must be a power of 2 and 19 | /// `x::bit_size() / no_subword % group_bit_size == 0` (that is, a subword must 20 | /// be divisible into bitgroups). 21 | /// 22 | /// # Examples 23 | /// 24 | /// ``` 25 | /// use bitwise::word::*; 26 | /// 27 | /// let n = 0b0101_1101_1010_0101_u16; 28 | /// 29 | /// // Reverse bits of `n`: 30 | /// assert_eq!(n.reverse_bit_groups(1u32, 1u32), 0b1010_0101_1011_1010u16); 31 | /// 32 | /// // Reverse bit pairs of `n`: 33 | /// assert_eq!(reverse_bit_groups(n, 2u32, 1u32), 0b0101_1010_0111_0101u16); 34 | /// 35 | /// // Reverse bit nibbles (groups of 4 bits) of `n`: 36 | /// assert_eq!(n.reverse_bit_groups(4u32, 1u32), 0b0101_1010_1101_0101u16); 37 | /// 38 | /// // Reverse the bits within each two 8-bit subwords of `n`: 39 | /// assert_eq!(n.reverse_bit_groups(1u32, 2u32), 0b1011_1010_1010_0101u16); 40 | /// 41 | /// // Reverse the bit pairs within each two-8 bit subwords of `n`: 42 | /// assert_eq!(n.reverse_bit_groups(2u32, 2u32), 0b0111_0101_0101_1010u16); 43 | /// 44 | /// // Reverse the bit nibbles within each two 8-bit subwords of `n`: 45 | /// assert_eq!(n.reverse_bit_groups(4u32, 2u32), 0b1101_0101_0101_1010u16); 46 | /// 47 | /// // Reverse bits within each four 4-bit subwords of `n`: 48 | /// assert_eq!(n.reverse_bit_groups(1u32, 4u32), 0b1010_1011_0101_1010u16); 49 | /// 50 | /// // Reverse bit pairs within each four 4-bit subwords of `n`: 51 | /// assert_eq!(n.reverse_bit_groups(2u32, 4u32), 0b0101_0111_1010_0101u16); 52 | /// 53 | /// // Reverse bits within each 8 2-bit subwords of `n`: 54 | /// assert_eq!(n.reverse_bit_groups(1u32, 8u32), 0b1010_1110_0101_1010u16); 55 | /// ``` 56 | #[inline] 57 | pub fn reverse_bit_groups(x: T, group_bit_size: U, no_subwords: U) -> T { 58 | // Adapted from Matthew Fioravante's stdcxx-bitops, which 59 | // is released under the MIT's License here: 60 | // https://github.com/fmatthew5876/stdcxx-bitops 61 | 62 | type TU where U: Word = U::Unsigned; // TODO: fix warning ? 63 | 64 | debug_assert!(group_bit_size.is_pow2()); 65 | debug_assert!(no_subwords.is_pow2()); 66 | 67 | let mut y: TU = x.to(); 68 | let width = T::byte_size(); 69 | let subword_bit_size = T::bit_size() / no_subwords.to(); 70 | debug_assert!(subword_bit_size.to_u32() % group_bit_size.to_u32() == 0); 71 | let k = subword_bit_size - group_bit_size.to(); 72 | { 73 | let mut up0 = |i, l, r| if k & i > 0.to() { 74 | y = ((y & l) << i.to()) | ((y & r) >> i.to()); 75 | }; 76 | 77 | up0(1.to(), 78 | 0x5555555555555555u64.to(), 79 | 0xAAAAAAAAAAAAAAAAu64.to()); 80 | up0(2.to(), 81 | 0x3333333333333333u64.to(), 82 | 0xCCCCCCCCCCCCCCCCu64.to()); 83 | up0(4.to(), 84 | 0x0F0F0F0F0F0F0F0Fu64.to(), 85 | 0xF0F0F0F0F0F0F0F0u64.to()); 86 | } 87 | 88 | { 89 | let mut up1 = |i, s, l, r| if width > i && (k & s > 0.to()) { 90 | y = ((y & l) << s.to()) | ((y & r) >> s.to()); 91 | }; 92 | 93 | up1(1.to(), 94 | 8.to(), 95 | 0x00FF00FF00FF00FFu64.to(), 96 | 0xFF00FF00FF00FF00u64.to()); 97 | up1(2.to(), 98 | 16.to(), 99 | 0x0000FFFF0000FFFFu64.to(), 100 | 0xFFFF0000FFFF0000u64.to()); 101 | up1(4.to(), 102 | 32.to(), 103 | 0x00000000FFFFFFFFu64.to(), 104 | 0xFFFFFFFF00000000u64.to()); 105 | } 106 | y.to() 107 | } 108 | 109 | /// Method version of [`reverse_bit_groups`](fn.reverse_bit_groups.html). 110 | pub trait ReverseBitGroups: Word { 111 | #[inline] 112 | fn reverse_bit_groups(self, x: T, y: T) -> Self; 113 | } 114 | 115 | impl ReverseBitGroups for T { 116 | #[inline] 117 | fn reverse_bit_groups(self, x: U, y: U) -> T { 118 | reverse_bit_groups(self, x, y) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/word/reverse_bit_nibbles.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | use word::reverse_bit_groups::*; 3 | 4 | /// Reverses the nibbles of `x`. 5 | /// 6 | /// # Examples 7 | /// 8 | /// ``` 9 | /// use bitwise::word::*; 10 | /// 11 | /// assert_eq!(0b1011_0010u8.reverse_bit_nibbles(), 0b0010_1011u8); 12 | /// assert_eq!(reverse_bit_nibbles(0b1011_0010_1010_1001u16), 0b1001_1010_0010_1011u16); 13 | /// ``` 14 | #[inline] 15 | pub fn reverse_bit_nibbles(x: T) -> T { 16 | reverse_bit_groups(x, 4u8, 1u8) 17 | } 18 | 19 | /// Method version of [`reverse_bit_nibbles`](fn.reverse_bit_nibbles.html). 20 | pub trait ReverseBitNibbles: Word { 21 | #[inline] 22 | fn reverse_bit_nibbles(self) -> Self; 23 | } 24 | 25 | impl ReverseBitNibbles for T { 26 | #[inline] 27 | fn reverse_bit_nibbles(self) -> T { 28 | reverse_bit_nibbles(self) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/word/reverse_bit_pairs.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | use word::reverse_bit_groups::*; 3 | 4 | /// Reverses the pairs of bits of `x`. 5 | /// 6 | /// # Examples 7 | /// 8 | /// ``` 9 | /// use bitwise::word::*; 10 | /// 11 | /// assert_eq!(0b1011_0010u8.reverse_bit_pairs(), 0b1000_1110u8); 12 | /// assert_eq!(reverse_bit_pairs(0b1011_0010_1010_1001u16), 0b0110_1010_1000_1110u16); 13 | /// ``` 14 | #[inline] 15 | pub fn reverse_bit_pairs(x: T) -> T { 16 | reverse_bit_groups(x, 2u8, 1u8) 17 | } 18 | 19 | /// Method version of [`reverse_bit_pairs`](fn.reverse_bit_pairs.html). 20 | pub trait ReverseBitPairs: Word { 21 | #[inline] 22 | fn reverse_bit_pairs(self) -> Self; 23 | } 24 | 25 | impl ReverseBitPairs for T { 26 | #[inline] 27 | fn reverse_bit_pairs(self) -> T { 28 | reverse_bit_pairs(self) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/word/reverse_bits.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Reverses the bits of `x`. 4 | /// 5 | /// # Intrinsics: 6 | /// - ARM: rbit (u32 ARMv7, u64 ARMv8). 7 | /// 8 | /// # Examples 9 | /// 10 | /// ``` 11 | /// use bitwise::word::*; 12 | /// 13 | /// assert_eq!(0b1011_0010u8.reverse_bits(), 0b0100_1101u8); 14 | /// assert_eq!(reverse_bits(0b1011_0010_1010_1001u16), 0b1001_0101_0100_1101u16); 15 | /// ``` 16 | #[inline] 17 | pub fn reverse_bits(x: T) -> T { 18 | x.rbit() 19 | } 20 | 21 | /// Method version of [`reverse_bits`](fn.reverse_bits.html). 22 | pub trait ReverseBits: Word { 23 | #[inline] 24 | fn reverse_bits(self) -> Self; 25 | } 26 | 27 | impl ReverseBits for T { 28 | #[inline] 29 | fn reverse_bits(self) -> T { 30 | reverse_bits(self) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/word/reverse_byte_groups.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, UnsignedWord, ToWord}; 2 | use word::reverse_bit_groups::*; 3 | 4 | /// Reverses groups of bytes within each subword of `x` 5 | /// 6 | /// * `group_byte_size` - The size (in bytes) of the groups of bytes to be 7 | /// reversed. 8 | /// * `no_subwords` - The number of subwords in `x`. 9 | /// 10 | /// The word `x` is divided into `no_subwords`. The byte groups of size 11 | /// `group_byte_size` are reversed within each subword. Bits within a byte group 12 | /// are _not_ reversed. 13 | /// 14 | /// The size in bits of a subword is thus `x::bit_size() / no_subword`. When 15 | /// `no_suboword == 1` the subword equals the original word. When 16 | /// `group_byte_size == 1` bytes are reversed within a subword. 17 | /// 18 | /// # Examples 19 | /// 20 | /// ``` 21 | /// use bitwise::word::*; 22 | /// 23 | /// // Single bytes: 24 | /// assert_eq!(0b0101_1101_1010_0101_u16.reverse_byte_groups(1u32, 1u32), 0b1010_0101_0101_1101u16); 25 | /// 26 | /// // Single bytes within two half-words: 27 | /// assert_eq!(reverse_byte_groups(0b0101_1101_1010_0101_0101_1101_1010_0101u32, 1u32, 2u32), 0b1010_0101_0101_1101_1010_0101_0101_1101u32); 28 | /// ``` 29 | #[inline] 30 | pub fn reverse_byte_groups(x: T, 31 | group_byte_size: U, 32 | no_subwords: U) 33 | -> T { 34 | reverse_bit_groups(x, group_byte_size * 8.to(), no_subwords) 35 | } 36 | 37 | /// Method version of [`reverse_byte_groups`](fn.reverse_byte_groups.html). 38 | pub trait ReverseByteGroups: Word { 39 | #[inline] 40 | fn reverse_byte_groups(self, group_byte_size: U, no_subwords: U) -> Self; 41 | } 42 | 43 | impl ReverseByteGroups for T { 44 | #[inline] 45 | fn reverse_byte_groups(self, group_byte_size: U, no_subwords: U) -> T { 46 | reverse_byte_groups(self, group_byte_size, no_subwords) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/word/reverse_bytes.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Reverses the bytes of `x`. 4 | /// 5 | /// Equivalent to swap bytes. 6 | /// 7 | /// # Intrinsics: 8 | /// - x86_64: bswap. 9 | /// - ARM: rev (v5), revsh (v5), rev16 (v6,v8), rev32(v8). 10 | /// - gcc/llvm: `__builtin_bswap16/32/64`. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// assert_eq!(0b1011_0010u8.reverse_bytes(), 0b1011_0010u8); 18 | /// assert_eq!(0b1011_0010_1010_1001u16.reverse_bytes(), 0b1010_1001_1011_0010u16); 19 | /// ``` 20 | #[inline] 21 | pub fn reverse_bytes(x: T) -> T { 22 | x.swap_bytes() 23 | } 24 | 25 | /// Method version of [`reverse_bytes`](fn.reverse_bytes.html). 26 | pub trait ReverseBytes: Word { 27 | #[inline] 28 | fn reverse_bytes(self) -> Self; 29 | } 30 | 31 | impl ReverseBytes for T { 32 | #[inline] 33 | fn reverse_bytes(self) -> T { 34 | reverse_bytes(self) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/rotate_left.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Shifts the bits of `x` to the left by `n` wrapping the truncated bits to the 4 | /// end of the result. 5 | /// 6 | /// # Panics 7 | /// 8 | /// If `n > bit_size()`. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// use bitwise::word::*; 14 | /// 15 | /// let n = 0x0123456789ABCDEFu64; 16 | /// let m = 0x3456789ABCDEF012u64; 17 | /// 18 | /// assert_eq!(n.rotate_left(12), m); 19 | /// rotate_left(n, u64::bit_size()); 20 | /// ``` 21 | #[inline] 22 | pub fn rotate_left(x: T, n: U) -> T { 23 | debug_assert!(n <= T::bit_size().to()); 24 | T::rotate_left(x, n.to()) 25 | } 26 | 27 | /// Method version of [`rotate_left`](fn.rotate_left.html). 28 | pub trait RotateLeft { 29 | #[inline] 30 | fn rotate_left(self, n: U) -> Self; 31 | } 32 | 33 | impl RotateLeft for T { 34 | #[inline] 35 | fn rotate_left(self, n: U) -> Self { 36 | rotate_left(self, n) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/word/rotate_right.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Shifts the bits of `x` to the right by `n` wrapping the truncated bits to 4 | /// the beginning of the result. 5 | /// 6 | /// # Panics 7 | /// 8 | /// If `n > bit_size()`. 9 | /// 10 | /// # Intrinsics: 11 | /// - BMI 2.0: rorx. 12 | /// 13 | /// # Examples 14 | /// 15 | /// ``` 16 | /// use bitwise::word::*; 17 | /// 18 | /// let n = 0x0123456789ABCDEFu64; 19 | /// let m = 0xDEF0123456789ABCu64; 20 | /// 21 | /// assert_eq!(n.rotate_right(12), m); 22 | /// rotate_right(n, u64::bit_size()); 23 | /// ``` 24 | #[inline] 25 | pub fn rotate_right(x: T, n: U) -> T { 26 | debug_assert!(n <= T::bit_size().to()); 27 | T::rotate_right(x, n.to()) 28 | } 29 | 30 | /// Method version of [`rotate_right`](fn.rotate_right.html). 31 | pub trait RotateRight { 32 | #[inline] 33 | fn rotate_right(self, n: U) -> Self; 34 | } 35 | 36 | impl RotateRight for T { 37 | #[inline] 38 | fn rotate_right(self, n: U) -> Self { 39 | rotate_right(self, n) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/word/set_bit.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Sets the `bit` of `x`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1011_0010u8; 15 | /// assert_eq!(n.set_bit(6u8), 0b1111_0010u8); 16 | /// assert_eq!(set_bit(n, 0u8), 0b1011_0011u8); 17 | /// assert_eq!(n.set_bit(3u8), 0b1011_1010u8); 18 | /// ``` 19 | #[inline] 20 | pub fn set_bit(x: T, bit: U) -> T { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x | (T::one() << bit.to()) 23 | } 24 | 25 | /// Method version of [`set_bit`](fn.set_bit.html). 26 | pub trait SetBit { 27 | #[inline] 28 | fn set_bit(self, n: U) -> Self; 29 | } 30 | 31 | impl SetBit for T { 32 | #[inline] 33 | fn set_bit(self, n: U) -> Self { 34 | set_bit(self, n) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/set_bits_geq.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Sets all bits of `x` at position >= `bit`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1000_0010u8; 15 | /// let s = 0b1110_0010u8; 16 | /// assert_eq!(n.set_bits_geq(5u8), s); 17 | /// assert_eq!(set_bits_geq(n, 5u8), s); 18 | /// ``` 19 | #[inline] 20 | pub fn set_bits_geq(x: T, bit: U) -> T { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x | !((T::one() << bit.to()) - T::one()) 23 | } 24 | 25 | /// Method version of [`set_bits_geq`](fn.set_bits_geq.html). 26 | pub trait SetBitsGeq { 27 | #[inline] 28 | fn set_bits_geq(self, n: U) -> Self; 29 | } 30 | 31 | impl SetBitsGeq for T { 32 | #[inline] 33 | fn set_bits_geq(self, n: U) -> Self { 34 | set_bits_geq(self, n) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/set_bits_leq.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Sets all bits of `x` at position <= `bit`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1000_0010u8; 15 | /// let s = 0b1011_1111u8; 16 | /// assert_eq!(n.set_bits_leq(5u8), s); 17 | /// assert_eq!(set_bits_leq(n, 5u8), s); 18 | /// ``` 19 | #[inline] 20 | pub fn set_bits_leq(x: T, bit: U) -> T { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x | ((T::one() << (T::one() + bit.to())) - T::one()) 23 | } 24 | 25 | /// Method version of [`set_bits_leq`](fn.set_bits_leq.html). 26 | pub trait SetBitsLeq { 27 | #[inline] 28 | fn set_bits_leq(self, n: U) -> Self; 29 | } 30 | 31 | impl SetBitsLeq for T { 32 | #[inline] 33 | fn set_bits_leq(self, n: U) -> Self { 34 | set_bits_leq(self, n) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/set_least_significant_zero.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Set least significant 0 bit of `x`. 4 | /// 5 | /// # Intrinsics: 6 | /// - TBM: blcs. 7 | /// 8 | /// # Examples 9 | /// 10 | /// ``` 11 | /// use bitwise::word::*; 12 | /// 13 | /// let n = 0b0101; 14 | /// let s = 0b0111; 15 | /// 16 | /// assert_eq!(n.set_least_significant_zero(), s); 17 | /// assert_eq!(set_least_significant_zero(n), s); 18 | /// ``` 19 | #[inline] 20 | pub fn set_least_significant_zero(x: T) -> T { 21 | x.blcs() 22 | } 23 | 24 | /// Method version of [`set_least_significant_zero`](fn.set_least_significant_zero.html). 25 | pub trait SetLeastSignificantZero { 26 | #[inline] 27 | fn set_least_significant_zero(self) -> Self; 28 | } 29 | 30 | impl SetLeastSignificantZero for T { 31 | #[inline] 32 | fn set_least_significant_zero(self) -> Self { 33 | set_least_significant_zero(self) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/word/set_trailing_zeros.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Set the trailing 0's of `x`. 4 | /// 5 | /// If all bits of `x` are set, returns `x`. 6 | /// 7 | /// # Intrinsics: 8 | /// - TBM: blsfill. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// use bitwise::word::*; 14 | /// 15 | /// let n = 0b0110_0000u8; 16 | /// let s = 0b0111_1111u8; 17 | /// 18 | /// assert_eq!(n.set_trailing_zeros(), s); 19 | /// assert_eq!(set_trailing_zeros(0b1111_1111u8), 0b1111_1111u8); 20 | /// ``` 21 | #[inline] 22 | pub fn set_trailing_zeros(x: T) -> T { 23 | x.blsfill() 24 | } 25 | 26 | /// Method version of [`set_trailing_zeros`](fn.set_trailing_zeros.html). 27 | pub trait SetTrailingZeros { 28 | #[inline] 29 | fn set_trailing_zeros(self) -> Self; 30 | } 31 | 32 | impl SetTrailingZeros for T { 33 | #[inline] 34 | fn set_trailing_zeros(self) -> Self { 35 | set_trailing_zeros(self) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/word/shift_arithmetic_left.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Shift the bits of `x` to the left by `n`. 4 | /// 5 | /// Same as [`shift_logical_left`](fn.shift_logical_left), provided for 6 | /// symmetry. 7 | /// 8 | /// # Panics 9 | /// 10 | /// If `n > bit_size()`. 11 | /// 12 | /// # Examples 13 | /// 14 | /// ``` 15 | /// use bitwise::word::*; 16 | /// 17 | /// let a = 0b0000_1010u8; 18 | /// let b = 0b0000_1001u8; 19 | /// 20 | /// assert_eq!(a.shift_arithmetic_left(4u8), 0b1010_0000u8); 21 | /// assert_eq!(shift_arithmetic_left(b, 4u8), 0b1001_0000u8); 22 | /// b.shift_arithmetic_left(u8::bit_size() - 1); 23 | /// ``` 24 | #[inline] 25 | pub fn shift_arithmetic_left(x: T, n: U) -> T { 26 | debug_assert!(n <= T::bit_size().to()); 27 | (x.to_unsigned() << n.to()).to() 28 | } 29 | 30 | /// Method version of [`shift_arithmetic_left`](fn.shift_arithmetic_left.html). 31 | pub trait SAL { 32 | #[inline] 33 | fn shift_arithmetic_left(self, n: U) -> Self; 34 | } 35 | 36 | impl SAL for T { 37 | #[inline] 38 | fn shift_arithmetic_left(self, n: U) -> Self { 39 | shift_arithmetic_left(self, n) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/word/shift_arithmetic_right.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Shift the bits of `x` to the right by `n`; the high-order bits of the result 4 | /// are set to the value of the most significant bit of `x`. 5 | /// 6 | /// # Panics 7 | /// 8 | /// If `n > bit_size()`. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// use bitwise::word::*; 14 | /// 15 | /// let a = 0b0111_0000u8; 16 | /// let b = 0b1001_0000u8; 17 | /// 18 | /// assert_eq!(a.shift_arithmetic_right(4u8), 0b0000_0111u8); 19 | /// assert_eq!(shift_arithmetic_right(b, 4u8), 0b1111_1001u8); 20 | /// b.shift_arithmetic_right(u8::bit_size() - 1); 21 | /// 22 | /// ``` 23 | #[inline] 24 | pub fn shift_arithmetic_right(x: T, n: U) -> T { 25 | debug_assert!(n <= T::bit_size().to()); 26 | (x.to_signed() >> n.to()).to() 27 | 28 | } 29 | 30 | /// Method version of [`shift_arithmetic_right`](fn.shift_arithmetic_right.html). 31 | pub trait SAR { 32 | #[inline] 33 | fn shift_arithmetic_right(self, n: U) -> Self; 34 | } 35 | 36 | impl SAR for T { 37 | #[inline] 38 | fn shift_arithmetic_right(self, n: U) -> Self { 39 | shift_arithmetic_right(self, n) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/word/shift_logical_left.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord}; 2 | 3 | /// Shift the bits to the left by a specified amount, `n`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `n > bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let a = 0b0000_1010u8; 15 | /// let b = 0b0000_1001u8; 16 | /// 17 | /// assert_eq!(shift_logical_left(a, 4), 0b1010_0000u8); 18 | /// assert_eq!(b.shift_logical_left(4), 0b1001_0000u8); 19 | /// 20 | /// ``` 21 | #[inline] 22 | pub fn shift_logical_left(x: T, n: U) -> T { 23 | debug_assert!(n <= T::bit_size().to()); 24 | (x.to_unsigned() << n.to_unsigned().to()).to() 25 | } 26 | 27 | /// Method version of [`shift_logical_left`](fn.shift_logical_left.html). 28 | pub trait SLL { 29 | #[inline] 30 | fn shift_logical_left(self, n: U) -> Self; 31 | } 32 | 33 | impl SLL for T { 34 | #[inline] 35 | fn shift_logical_left(self, n: U) -> Self { 36 | shift_logical_left(self, n) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/word/shift_logical_right.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord}; 2 | 3 | /// Shift the bits of `x` to the right `n`; the 4 | /// high-order bits of the result are cleared. 5 | /// 6 | /// # Panics 7 | /// 8 | /// If `n > bit_size()`. 9 | /// 10 | /// # Examples 11 | /// 12 | /// 13 | /// ``` 14 | /// use bitwise::word::*; 15 | /// 16 | /// let a = 0b0111_0000u8; 17 | /// let b = 0b1001_0000u8; 18 | /// 19 | /// assert_eq!(a.shift_logical_right(4), 0b0000_0111u8); 20 | /// assert_eq!(shift_logical_right(b, 4), 0b0000_1001u8); 21 | /// b.shift_logical_right((u8::bit_size() - 1)); 22 | /// ``` 23 | #[inline] 24 | pub fn shift_logical_right(x: T, n: U) -> T { 25 | debug_assert!(n <= T::bit_size().to()); 26 | (x.to_unsigned() >> n.to_unsigned().to()).to() 27 | } 28 | 29 | /// Method version of [`shift_logical_right`](fn.shift_logical_right.html). 30 | pub trait SLR { 31 | #[inline] 32 | fn shift_logical_right(self, n: U) -> Self; 33 | } 34 | 35 | impl SLR for T { 36 | #[inline] 37 | fn shift_logical_right(self, n: U) -> Self { 38 | shift_logical_right(self, n) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/word/swap_bytes.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Reverses the order of the bytes of `x`. 4 | /// 5 | /// # Examples 6 | /// 7 | /// ``` 8 | /// use bitwise::word::*; 9 | /// 10 | /// let n = 0x0123456789ABCDEFu64; 11 | /// let m = 0xEFCDAB8967452301u64; 12 | /// 13 | /// assert_eq!(n.swap_bytes(), m); 14 | /// assert_eq!(swap_bytes(n), m); 15 | /// ``` 16 | #[inline] 17 | pub fn swap_bytes(x: T) -> T { 18 | T::swap_bytes(x) 19 | } 20 | 21 | /// Method version of [`swap_bytes`](fn.swap_bytes.html). 22 | pub trait SwapBytes { 23 | #[inline] 24 | fn swap_bytes(self) -> Self; 25 | } 26 | 27 | impl SwapBytes for T { 28 | #[inline] 29 | fn swap_bytes(self) -> Self { 30 | swap_bytes(self) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/word/test_bit.rs: -------------------------------------------------------------------------------- 1 | use word::{Word, ToWord, UnsignedWord}; 2 | 3 | /// Test the `bit` of `x`. 4 | /// 5 | /// # Panics 6 | /// 7 | /// If `bit >= bit_size()`. 8 | /// 9 | /// # Examples 10 | /// 11 | /// ``` 12 | /// use bitwise::word::*; 13 | /// 14 | /// let n = 0b1011_0010u8; 15 | /// assert_eq!(test_bit(n, 7u8), true); 16 | /// assert_eq!(n.test_bit(6u8), false); 17 | /// assert_eq!(n.test_bit(5u8), true); 18 | /// ``` 19 | #[inline] 20 | pub fn test_bit(x: T, bit: U) -> bool { 21 | debug_assert!(T::bit_size() > bit.to()); 22 | x & (T::one() << bit.to()) != T::zero() 23 | } 24 | 25 | /// Method version of [`test_bit`](fn.test_bit.html). 26 | pub trait TestBit { 27 | #[inline] 28 | fn test_bit(self, n: U) -> bool; 29 | } 30 | 31 | impl TestBit for T { 32 | #[inline] 33 | fn test_bit(self, n: U) -> bool { 34 | test_bit(self, n) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/word/to_be.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Convert `x` to big endian from the target's endianness. 4 | /// 5 | /// On big endian this is a no-op. On little endian the bytes are swapped. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use bitwise::word::*; 11 | /// 12 | /// let n = 0x0123456789ABCDEFu64; 13 | /// 14 | /// if cfg!(target_endian = "big") { 15 | /// assert_eq!(n.to_be(), n); 16 | /// assert_eq!(to_be(n), n); 17 | /// } else { 18 | /// assert_eq!(n.to_be(), n.swap_bytes()); 19 | /// assert_eq!(to_be(n), n.swap_bytes()); 20 | /// } 21 | /// ``` 22 | #[inline] 23 | pub fn to_be(x: T) -> T { 24 | T::to_be(x) 25 | } 26 | -------------------------------------------------------------------------------- /src/word/to_le.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Convert `x` to little endian from the target's endianness. 4 | /// 5 | /// On little endian this is a no-op. On big endian the bytes are swapped. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ``` 10 | /// use bitwise::word::*; 11 | /// 12 | /// let n = 0x0123456789ABCDEFu64; 13 | /// 14 | /// if cfg!(target_endian = "little") { 15 | /// assert_eq!(n.to_le(), n); 16 | /// assert_eq!(to_le(n), n); 17 | /// } else { 18 | /// assert_eq!(n.to_le(), n.swap_bytes()); 19 | /// assert_eq!(to_le(n), n.swap_bytes()); 20 | /// } 21 | /// ``` 22 | #[inline] 23 | pub fn to_le(x: T) -> T { 24 | T::to_le(x) 25 | } 26 | -------------------------------------------------------------------------------- /src/word/to_word.rs: -------------------------------------------------------------------------------- 1 | use word::Word; 2 | 3 | /// Unsigned word. 4 | pub trait UnsignedWord: Word {} 5 | impl UnsignedWord for u8 {} 6 | impl UnsignedWord for u16 {} 7 | impl UnsignedWord for u32 {} 8 | impl UnsignedWord for u64 {} 9 | 10 | /// From-like trait for words. 11 | pub trait FromWord { 12 | /// Converts a `T` to `Self`. 13 | #[inline] 14 | fn from(T) -> Self; 15 | } 16 | 17 | macro_rules! impl_from_word_from_to { 18 | ($From:ty, $To:ty) => ( 19 | impl FromWord<$From> for $To { 20 | #[inline] fn from(x: $From) -> Self { 21 | x as Self 22 | } 23 | } 24 | ) 25 | } 26 | 27 | macro_rules! impl_from_word_multiple { 28 | ($From:ty, $To:ty) => ( 29 | impl_from_word_from_to!($From, $To); 30 | ); 31 | ($From:ty, $To:ty $(, $Rest:ty)+) => ( 32 | impl_from_word_multiple!($From, $To); 33 | impl_from_word_multiple!($From, $($Rest),*); 34 | ) 35 | } 36 | 37 | macro_rules! impl_from_word { 38 | ($From:ty) => ( 39 | impl_from_word_multiple!($From, i8, i16, i32, i64, 40 | u8, u16, u32, u64); 41 | ) 42 | } 43 | 44 | impl_from_word!(i8); 45 | impl_from_word!(i16); 46 | impl_from_word!(i32); 47 | impl_from_word!(i64); 48 | impl_from_word!(u8); 49 | impl_from_word!(u16); 50 | impl_from_word!(u32); 51 | impl_from_word!(u64); 52 | 53 | impl FromWord for U { 54 | #[inline] 55 | default fn from(x: T) -> Self { 56 | ToWord::to(x) 57 | } 58 | } 59 | 60 | /// Into-like trait for words. 61 | pub trait ToWord { 62 | /// Converts self to `T`. 63 | #[inline] 64 | fn to(self) -> T; 65 | } 66 | 67 | // From implies Into 68 | impl ToWord for T 69 | where U: FromWord 70 | { 71 | #[inline] 72 | fn to(self) -> U { 73 | U::from(self) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/word/word.rs: -------------------------------------------------------------------------------- 1 | //! Generic Integer traits. 2 | 3 | use std::ops::{Add, Sub, Mul, Div, Rem}; 4 | use std::ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; 5 | use std::cmp::{PartialEq, PartialOrd}; 6 | use std::mem::size_of; 7 | 8 | use bitintr::*; 9 | 10 | /// Integer trait used to parametrize algorithms for all integer types. 11 | pub trait Word 12 | : Sized 13 | + Copy 14 | + Add 15 | + Sub 16 | + Mul 17 | + Div 18 | + Rem 19 | + Not 20 | + BitAnd 21 | + BitOr 22 | + BitXor 23 | + Shr 24 | + Shl 25 | + PartialEq + PartialOrd 26 | + Bzhi 27 | + Blsr 28 | + Blcfill 29 | + Lzcnt 30 | + Popcnt 31 | + Tzcnt 32 | + Bextr 33 | + Popcnt 34 | + Blsi 35 | + Blcic 36 | + Blcmsk 37 | + T1mskc 38 | + Blsmsk 39 | + Tzmsk 40 | + Pdep 41 | + Pext 42 | + Rbit 43 | + Blcs 44 | + Blsfill 45 | { 46 | type Unsigned: Word; 47 | type Signed: Word; 48 | #[inline] fn one() -> Self; 49 | #[inline] fn zero() -> Self; 50 | #[inline] fn byte_size() -> Self; 51 | #[inline] fn bit_size() -> Self; 52 | #[inline] fn count_ones(self) -> Self; 53 | #[inline] fn count_zeros(self) -> Self; 54 | #[inline] fn leading_zeros(self) -> Self; 55 | #[inline] fn trailing_zeros(self) -> Self; 56 | #[inline] fn wrapping_neg(self) -> Self; 57 | #[inline] fn wrapping_add(self, Self) -> Self; 58 | #[inline] fn wrapping_sub(self, Self) -> Self; 59 | #[inline] fn wrapping_shl(self, Self) -> Self; 60 | #[inline] fn wrapping_shr(self, Self) -> Self; 61 | #[inline] fn to_u8(self) -> u8; 62 | #[inline] fn to_u16(self) -> u16; 63 | #[inline] fn to_u32(self) -> u32; 64 | #[inline] fn to_u64(self) -> u64; 65 | #[inline] fn to_i8(self) -> i8; 66 | #[inline] fn to_i16(self) -> i16; 67 | #[inline] fn to_i32(self) -> i32; 68 | #[inline] fn to_i64(self) -> i64; 69 | #[inline] fn from_u8(u8) -> Self; 70 | #[inline] fn from_u16(u16) -> Self; 71 | #[inline] fn from_u32(u32) -> Self; 72 | #[inline] fn from_u64(u64) -> Self; 73 | #[inline] fn from_i8(i8) -> Self; 74 | #[inline] fn from_i16(i16) -> Self; 75 | #[inline] fn from_i32(i32) -> Self; 76 | #[inline] fn from_i64(i64) -> Self; 77 | #[inline] fn rotate_left(self, u32) -> Self; 78 | #[inline] fn rotate_right(self, u32) -> Self; 79 | #[inline] fn swap_bytes(self) -> Self; 80 | #[inline] fn from_be(self) -> Self; 81 | #[inline] fn from_le(self) -> Self; 82 | #[inline] fn to_be(self) -> Self; 83 | #[inline] fn to_le(self) -> Self; 84 | #[inline] fn pow(self, exp: u32) -> Self; 85 | #[inline] fn to_unsigned(self) -> Self::Unsigned; 86 | #[inline] fn to_signed(self) -> Self::Signed; 87 | #[inline] fn from_unsigned(Self::Unsigned) -> Self; 88 | #[inline] fn from_signed(Self::Signed) -> Self; 89 | #[inline] fn to_usize(self) -> usize; 90 | } 91 | 92 | macro_rules! int_impl { 93 | ($T:ty, $UT:ty, $ST:ty) => ( 94 | impl Word for $T { 95 | type Unsigned = $UT; 96 | type Signed = $ST; 97 | #[inline] fn one() -> Self { 1 as Self } 98 | #[inline] fn zero() -> Self { 0 as Self } 99 | 100 | #[inline] fn byte_size() -> Self { 101 | size_of::() as Self 102 | } 103 | 104 | #[inline] fn bit_size() -> Self { 105 | (Self::byte_size() * 8) as Self 106 | } 107 | 108 | #[inline] fn count_ones(self) -> $T { 109 | self.count_ones() as $T 110 | } 111 | #[inline] fn count_zeros(self) -> $T { 112 | self.count_zeros() as $T 113 | } 114 | #[inline] fn leading_zeros(self) -> $T { 115 | self.leading_zeros() as $T 116 | } 117 | #[inline] fn trailing_zeros(self) -> $T { 118 | self.trailing_zeros() as $T 119 | } 120 | #[inline] fn wrapping_neg(self) -> $T { 121 | self.wrapping_neg() as $T 122 | } 123 | #[inline] fn wrapping_add(self, o: Self) -> $T { 124 | self.wrapping_add(o) as $T 125 | } 126 | #[inline] fn wrapping_sub(self, o: Self) -> $T { 127 | self.wrapping_sub(o) as $T 128 | } 129 | #[inline] fn wrapping_shl(self, o: Self) -> $T { 130 | self.wrapping_shl(o as u32) as $T 131 | } 132 | #[inline] fn wrapping_shr(self, o: Self) -> $T { 133 | self.wrapping_shr(o as u32) as $T 134 | } 135 | 136 | #[inline] fn to_u8(self) -> u8 { self as u8 } 137 | #[inline] fn to_u16(self) -> u16 { self as u16 } 138 | #[inline] fn to_u32(self) -> u32 { self as u32 } 139 | #[inline] fn to_u64(self) -> u64 { self as u64 } 140 | #[inline] fn to_i8(self) -> i8 { self as i8 } 141 | #[inline] fn to_i16(self) -> i16 { self as i16 } 142 | #[inline] fn to_i32(self) -> i32 { self as i32 } 143 | #[inline] fn to_i64(self) -> i64 { self as i64 } 144 | #[inline] fn from_u8(x: u8) -> Self { x as Self } 145 | #[inline] fn from_u16(x: u16) -> Self { x as Self } 146 | #[inline] fn from_u32(x: u32) -> Self { x as Self } 147 | #[inline] fn from_u64(x: u64) -> Self { x as Self } 148 | #[inline] fn from_i8(x: i8) -> Self { x as Self } 149 | #[inline] fn from_i16(x: i16) -> Self { x as Self } 150 | #[inline] fn from_i32(x: i32) -> Self { x as Self } 151 | #[inline] fn from_i64(x: i64) -> Self { x as Self } 152 | 153 | #[inline] fn rotate_left(self, n: u32) -> Self { (self as $T).rotate_left(n) } 154 | #[inline] fn rotate_right(self, n: u32) -> Self { (self as $T).rotate_right(n) } 155 | #[inline] fn swap_bytes(self) -> Self { <$T>::swap_bytes(self) } 156 | 157 | #[inline] fn from_be(self) -> Self { 158 | <$T>::from_be(self) 159 | } 160 | 161 | #[inline] fn from_le(self) -> Self { 162 | <$T>::from_le(self) 163 | } 164 | 165 | #[inline] fn to_be(self) -> Self { 166 | <$T>::to_be(self) 167 | } 168 | 169 | #[inline] fn to_le(self) -> Self { 170 | <$T>::to_le(self) 171 | } 172 | 173 | #[inline] fn pow(self, exp: u32) -> Self { 174 | <$T>::pow(self, exp) 175 | } 176 | 177 | #[inline] fn to_unsigned(self) -> Self::Unsigned { 178 | self as $UT 179 | } 180 | #[inline] fn to_signed(self) -> Self::Signed { 181 | self as $ST 182 | } 183 | #[inline] fn from_unsigned(x: Self::Unsigned) -> Self { 184 | x as $T 185 | } 186 | #[inline] fn from_signed(x: Self::Signed) -> Self { 187 | x as $T 188 | } 189 | 190 | #[inline] fn to_usize(self) -> usize { 191 | self as usize 192 | } 193 | } 194 | ) 195 | } 196 | 197 | 198 | int_impl!(u8, u8, i8); 199 | int_impl!(u16, u16, i16); 200 | int_impl!(u32, u32, i32); 201 | int_impl!(u64, u64, i64); 202 | 203 | int_impl!(i8, u8, i8); 204 | int_impl!(i16, u16, i16); 205 | int_impl!(i32, u32, i32); 206 | int_impl!(i64, u64, i64); 207 | --------------------------------------------------------------------------------