Merge pull request #28 from pickfire/branchless

Use branchless binary search to find_min_version
This commit is contained in:
kennytm 2019-07-06 23:46:22 +08:00 committed by GitHub
commit 0a4c64842d

View file

@ -3,7 +3,7 @@
use std::cmp::min; use std::cmp::min;
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
use test::Bencher; use test::{black_box, Bencher};
use cast::{As, Truncate}; use cast::{As, Truncate};
use optimize::{total_encoded_len, Optimizer, Parser, Segment}; use optimize::{total_encoded_len, Optimizer, Parser, Segment};
@ -859,17 +859,20 @@ pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult<Bits> {
/// Finds the smallest version (QR code only) that can store N bits of data /// Finds the smallest version (QR code only) that can store N bits of data
/// in the given error correction level. /// in the given error correction level.
fn find_min_version(length: usize, ec_level: EcLevel) -> Version { fn find_min_version(length: usize, ec_level: EcLevel) -> Version {
let mut min = 0; let mut base = 0usize;
let mut max = 39; let mut size = 39;
while min < max { while size > 1 {
let half = (min + max) / 2; let half = size / 2;
if DATA_LENGTHS[half][ec_level as usize] < length { let mid = base + half;
min = half + 1; // mid is always in [0, size).
} else { // mid >= 0: by definition
max = half; // mid < size: mid = size / 2 + size / 4 + size / 8 ...
} base = if DATA_LENGTHS[mid][ec_level as usize] > length { base } else { mid };
size -= half;
} }
Version::Normal((min + 1).as_i16()) // base is always in [0, mid) because base <= mid.
base = if DATA_LENGTHS[base][ec_level as usize] >= length { base } else { base + 1 };
Version::Normal((base + 1).as_i16())
} }
#[cfg(test)] #[cfg(test)]
@ -907,5 +910,19 @@ mod encode_auto_tests {
} }
} }
#[cfg(feature = "bench")]
#[bench]
fn bench_find_min_version(bencher: &mut Bencher) {
bencher.iter(|| {
black_box(find_min_version(60, EcLevel::L));
black_box(find_min_version(200, EcLevel::L));
black_box(find_min_version(200, EcLevel::H));
black_box(find_min_version(20000, EcLevel::L));
black_box(find_min_version(640, EcLevel::L));
black_box(find_min_version(641, EcLevel::L));
black_box(find_min_version(999999, EcLevel::H));
})
}
//}}} //}}}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------