Skip to content

Commit 8ee1918

Browse files
authored
Merge pull request #28 from pickfire/branchless
Use branchless binary search to find_min_version
2 parents a585403 + 81404ac commit 8ee1918

File tree

1 file changed

+29
-12
lines changed

1 file changed

+29
-12
lines changed

src/bits.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::cmp::min;
44

55
#[cfg(feature = "bench")]
6-
use test::Bencher;
6+
use test::{black_box, Bencher};
77

88
use cast::{As, Truncate};
99
use optimize::{total_encoded_len, Optimizer, Parser, Segment};
@@ -859,17 +859,20 @@ pub fn encode_auto(data: &[u8], ec_level: EcLevel) -> QrResult<Bits> {
859859
/// Finds the smallest version (QR code only) that can store N bits of data
860860
/// in the given error correction level.
861861
fn find_min_version(length: usize, ec_level: EcLevel) -> Version {
862-
let mut min = 0;
863-
let mut max = 39;
864-
while min < max {
865-
let half = (min + max) / 2;
866-
if DATA_LENGTHS[half][ec_level as usize] < length {
867-
min = half + 1;
868-
} else {
869-
max = half;
870-
}
871-
}
872-
Version::Normal((min + 1).as_i16())
862+
let mut base = 0usize;
863+
let mut size = 39;
864+
while size > 1 {
865+
let half = size / 2;
866+
let mid = base + half;
867+
// mid is always in [0, size).
868+
// mid >= 0: by definition
869+
// mid < size: mid = size / 2 + size / 4 + size / 8 ...
870+
base = if DATA_LENGTHS[mid][ec_level as usize] > length { base } else { mid };
871+
size -= half;
872+
}
873+
// base is always in [0, mid) because base <= mid.
874+
base = if DATA_LENGTHS[base][ec_level as usize] >= length { base } else { base + 1 };
875+
Version::Normal((base + 1).as_i16())
873876
}
874877

875878
#[cfg(test)]
@@ -907,5 +910,19 @@ mod encode_auto_tests {
907910
}
908911
}
909912

913+
#[cfg(feature = "bench")]
914+
#[bench]
915+
fn bench_find_min_version(bencher: &mut Bencher) {
916+
bencher.iter(|| {
917+
black_box(find_min_version(60, EcLevel::L));
918+
black_box(find_min_version(200, EcLevel::L));
919+
black_box(find_min_version(200, EcLevel::H));
920+
black_box(find_min_version(20000, EcLevel::L));
921+
black_box(find_min_version(640, EcLevel::L));
922+
black_box(find_min_version(641, EcLevel::L));
923+
black_box(find_min_version(999999, EcLevel::H));
924+
})
925+
}
926+
910927
//}}}
911928
//------------------------------------------------------------------------------

0 commit comments

Comments
 (0)