1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
use std::cmp::Ordering::{self, Equal, Greater, Less};
pub fn compare(left: &[u8], right: &[u8]) -> Ordering {
let mut left = left.into_iter().fuse();
let mut right = right.into_iter().fuse();
let mut l;
let mut r;
let mut ll;
let mut rr;
macro_rules! to_digit {
($v:expr) => {
$v.and_then(|v| {
let v = *v as isize;
(v >= ('0' as isize) && v <= ('9' as isize)).then_some(v - 48)
})
};
}
macro_rules! read_left {
() => {{
l = left.next();
ll = to_digit!(l);
}};
}
macro_rules! read_right {
() => {{
r = right.next();
rr = to_digit!(r);
}};
}
macro_rules! return_unless_equal {
($ord:expr) => {
match $ord {
Equal => {}
lastcmp => return lastcmp,
}
};
}
read_left!();
read_right!();
'nondigits: loop {
match (l, r) {
(Some(l_), Some(r_)) => match (ll, rr) {
(Some(ll_), Some(rr_)) => {
if ll_ == 0 || rr_ == 0 {
// left-aligned matching. (`015` < `12`)
return_unless_equal!(ll_.cmp(&rr_));
'digits_left: loop {
read_left!();
read_right!();
match (ll, rr) {
(Some(ll_), Some(rr_)) => return_unless_equal!(ll_.cmp(&rr_)),
(Some(_), None) => return Greater,
(None, Some(_)) => return Less,
(None, None) => break 'digits_left,
}
}
} else {
// right-aligned matching. (`15` < `123`)
let mut lastcmp = ll_.cmp(&rr_);
'digits_right: loop {
read_left!();
read_right!();
match (ll, rr) {
(Some(ll_), Some(rr_)) => {
// `lastcmp` is only used when there are the same number of
// digits, so we only update it.
if lastcmp == Equal {
lastcmp = ll_.cmp(&rr_);
}
}
(Some(_), None) => return Greater,
(None, Some(_)) => return Less,
(None, None) => break 'digits_right,
}
}
return_unless_equal!(lastcmp);
}
continue 'nondigits; // do not read from the iterators again
}
(_, _) => return_unless_equal!(l_.cmp(r_)),
},
(Some(_), None) => return Greater,
(None, Some(_)) => return Less,
(None, None) => return Equal,
}
read_left!();
read_right!();
}
}