fmt-cmp 0.1.2

Traits and utilities for lexicographically comparing values in their `Display` representations
Documentation
#![feature(test)]

extern crate test;

use std::cmp::Ordering;
use std::fmt::Display;
use test::Bencher;

const D1L: u64 = 9;
const D1R: u64 = 1;
const D4L: u64 = 9_876;
const D4R: u64 = 1_234;
const D4A: u64 = 9_874;
const D16L: u64 = 9_876_543_210_123_456;
const D16R: u64 = 1_234_567_890_987_654;
const D16A: u64 = 9_876_543_210_123_454;

macro_rules! bench {
    (
        $cmp:expr;
        $(#[$attr:meta])*
        $name_1_eq:ident; $name_1_ne:ident;
        $name_4_eq:ident; $name_4_ne:ident; $name_4_approxeq:ident;
        $name_16_eq:ident; $name_16_ne:ident; $name_16_approxeq:ident;
        $name_4_16:ident;
    ) => {
        bench! { @fn $(#[$attr])* $name_1_eq(D1L, D1L) = $cmp }
        bench! { @fn $(#[$attr])* $name_1_ne(D1L, D1R) = $cmp }
        bench! { @fn $(#[$attr])* $name_4_eq(D4L, D4L) = $cmp }
        bench! { @fn $(#[$attr])* $name_4_approxeq(D4L, D4A) = $cmp }
        bench! { @fn $(#[$attr])* $name_4_ne(D4L, D4R) = $cmp }
        bench! { @fn $(#[$attr])* $name_16_eq(D16L, D16L) = $cmp }
        bench! { @fn $(#[$attr])* $name_16_ne(D16L, D16R) = $cmp }
        bench! { @fn $(#[$attr])* $name_16_approxeq(D16L, D16A) = $cmp }
        bench! { @fn $(#[$attr])* $name_4_16(D4L, D16R) = $cmp }
    };
    (@fn $(#[$attr:meta])* $name:ident($lhs:expr, $rhs:expr) = $cmp:expr) => {
        $(#[$attr])*
        #[bench]
        fn $name(b: &mut Bencher) {
            // Take `$cmp` as `impl Fn` so that type inference works on closure arguments.
            fn run(cmp: impl Fn(&u64, &u64) -> Ordering) -> (Ordering, Ordering) {
                let (lhs, rhs) = test::black_box(($lhs, $rhs));
                (cmp(&lhs, &rhs), cmp(&rhs, &lhs))
            }
            b.iter(|| run($cmp));
        }
    };
}

bench! {
    u64::cmp;
    #[ignore]
    native_01_digit_eq; native_01_digit_ne;
    native_04_digits_eq; native_04_digits_ne; native_04_digits_approxeq;
    native_16_digits_eq; native_16_digits_ne; native_16_digits_approxeq;
    native_04_16_digits;
}

bench! {
    |lhs, rhs| (*lhs.to_string()).cmp(&*rhs.to_string());
    #[ignore]
    to_string_01_digit_eq; to_string_01_digit_ne;
    to_string_04_digits_eq; to_string_04_digits_ne; to_string_04_digits_approxeq;
    to_string_16_digits_eq; to_string_16_digits_ne; to_string_16_digits_approxeq;
    to_string_04_16_digits;
}

bench! {
    |&lhs, &rhs| {
        let (mut lbuf, mut rbuf) = (itoa::Buffer::new(), itoa::Buffer::new());
        let (lhs, rhs) = (lbuf.format(lhs), rbuf.format(rhs));
        lhs.cmp(rhs)
    };
    itoa_01_digit_eq; itoa_01_digit_ne;
    itoa_04_digits_eq; itoa_04_digits_ne; itoa_04_digits_approxeq;
    itoa_16_digits_eq; itoa_16_digits_ne; itoa_16_digits_approxeq;
    itoa_04_16_digits;
}

bench! {
    fmt_cmp::cmp;
    fmt_cmp_01_digit_eq; fmt_cmp_01_digit_ne;
    fmt_cmp_04_digits_eq; fmt_cmp_04_digits_ne; fmt_cmp_04_digits_approxeq;
    fmt_cmp_16_digits_eq; fmt_cmp_16_digits_ne; fmt_cmp_16_digits_approxeq;
    fmt_cmp_04_16_digits;
}

bench! {
    |lhs, rhs| {
        let (lhs, rhs) = test::black_box::<(&dyn Display, &dyn Display)>((lhs, rhs));
        fmt_cmp::cmp(lhs, rhs)
    };
    fmt_cmp_dyn_01_digit_eq; fmt_cmp_dyn_01_digit_ne;
    fmt_cmp_dyn_04_digits_eq; fmt_cmp_dyn_04_digits_ne; fmt_cmp_dyn_04_digits_approxeq;
    fmt_cmp_dyn_16_digits_eq; fmt_cmp_dyn_16_digits_ne; fmt_cmp_dyn_16_digits_approxeq;
    fmt_cmp_dyn_04_16_digits;
}

bench! {
    |&lhs, &rhs| fmt_cmp::cmp_int(lhs, rhs, 10);
    cmp_int_01_digit_eq; cmp_int_01_digit_ne;
    cmp_int_04_digits_eq; cmp_int_04_digits_ne; cmp_int_04_digits_approxeq;
    cmp_int_16_digits_eq; cmp_int_16_digits_ne; cmp_int_16_digits_approxeq;
    cmp_int_04_16_digits;
}

bench! {
    |&lhs, &rhs| fmt_cmp::cmp_dec(lhs, rhs);
    cmp_dec_01_digit_eq; cmp_dec_01_digit_ne;
    cmp_dec_04_digits_eq; cmp_dec_04_digits_ne; cmp_dec_04_digits_approxeq;
    cmp_dec_16_digits_eq; cmp_dec_16_digits_ne; cmp_dec_16_digits_approxeq;
    cmp_dec_04_16_digits;
}

#[bench]
fn cmp_hex_format_args(b: &mut Bencher) {
    let (lhs, rhs) = test::black_box((0xfedcba987654321_u64, 0x123456789abcdef_u64));
    b.iter(|| {
        (
            fmt_cmp::cmp(&format_args!("{:x}", lhs), &format_args!("{:x}", rhs)),
            fmt_cmp::cmp(&format_args!("{:x}", rhs), &format_args!("{:x}", lhs)),
        )
    })
}

#[bench]
fn cmp_hex_int(b: &mut Bencher) {
    let (lhs, rhs) = test::black_box((0xfedcba987654321_u64, 0x123456789abcdef_u64));
    b.iter(|| {
        (
            fmt_cmp::cmp_int(lhs, rhs, 16),
            fmt_cmp::cmp_int(lhs, rhs, 16),
        )
    })
}