| 1 | // Copyright 2012-2025 The Rust Project Developers. See the COPYRIGHT |
| 2 | // file at the top-level directory of this distribution and at |
| 3 | // http://rust-lang.org/COPYRIGHT. |
| 4 | // |
| 5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| 8 | // option. This file may not be copied, modified, or distributed |
| 9 | // except according to those terms. |
| 10 | #![feature(test)] |
| 11 | |
| 12 | extern crate test; |
| 13 | |
| 14 | use std::iter; |
| 15 | |
| 16 | use test::Bencher; |
| 17 | |
| 18 | use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; |
| 19 | |
| 20 | #[bench] |
| 21 | fn cargo(b: &mut Bencher) { |
| 22 | let string = iter::repeat('a').take(4096).collect::<String>(); |
| 23 | |
| 24 | b.iter(|| { |
| 25 | for c in string.chars() { |
| 26 | test::black_box(UnicodeWidthChar::width(c)); |
| 27 | } |
| 28 | }); |
| 29 | } |
| 30 | |
| 31 | #[bench] |
| 32 | #[allow(deprecated)] |
| 33 | fn stdlib(b: &mut Bencher) { |
| 34 | let string = iter::repeat('a').take(4096).collect::<String>(); |
| 35 | |
| 36 | b.iter(|| { |
| 37 | for c in string.chars() { |
| 38 | test::black_box(c.width()); |
| 39 | } |
| 40 | }); |
| 41 | } |
| 42 | |
| 43 | #[bench] |
| 44 | fn simple_if(b: &mut Bencher) { |
| 45 | let string = iter::repeat('a').take(4096).collect::<String>(); |
| 46 | |
| 47 | b.iter(|| { |
| 48 | for c in string.chars() { |
| 49 | test::black_box(simple_width_if(c)); |
| 50 | } |
| 51 | }); |
| 52 | } |
| 53 | |
| 54 | #[bench] |
| 55 | fn simple_match(b: &mut Bencher) { |
| 56 | let string = iter::repeat('a').take(4096).collect::<String>(); |
| 57 | |
| 58 | b.iter(|| { |
| 59 | for c in string.chars() { |
| 60 | test::black_box(simple_width_match(c)); |
| 61 | } |
| 62 | }); |
| 63 | } |
| 64 | |
| 65 | #[inline] |
| 66 | fn simple_width_if(c: char) -> Option<usize> { |
| 67 | let cu = c as u32; |
| 68 | if cu < 127 { |
| 69 | if cu > 31 { |
| 70 | Some(1) |
| 71 | } else if cu == 0 { |
| 72 | Some(0) |
| 73 | } else { |
| 74 | None |
| 75 | } |
| 76 | } else { |
| 77 | UnicodeWidthChar::width(c) |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | #[inline] |
| 82 | fn simple_width_match(c: char) -> Option<usize> { |
| 83 | match c as u32 { |
| 84 | cu if cu == 0 => Some(0), |
| 85 | cu if cu < 0x20 => None, |
| 86 | cu if cu < 0x7f => Some(1), |
| 87 | _ => UnicodeWidthChar::width(c), |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | #[bench] |
| 92 | fn enwik8(b: &mut Bencher) { |
| 93 | // To benchmark, download & unzip `enwik8` from https://data.deepai.org/enwik8.zip |
| 94 | let data_path = "bench_data/enwik8"; |
| 95 | let string = std::fs::read_to_string(data_path).unwrap_or_default(); |
| 96 | b.iter(|| test::black_box(UnicodeWidthStr::width(string.as_str()))); |
| 97 | } |
| 98 | |
| 99 | #[bench] |
| 100 | fn jawiki(b: &mut Bencher) { |
| 101 | // To benchmark, download & extract `jawiki-20220501-pages-articles-multistream-index.txt` from |
| 102 | // https://dumps.wikimedia.org/jawiki/20220501/jawiki-20220501-pages-articles-multistream-index.txt.bz2 |
| 103 | let data_path = "bench_data/jawiki-20220501-pages-articles-multistream-index.txt"; |
| 104 | let string = std::fs::read_to_string(data_path).unwrap_or_default(); |
| 105 | b.iter(|| test::black_box(UnicodeWidthStr::width(string.as_str()))); |
| 106 | } |
| 107 | |
| 108 | #[bench] |
| 109 | fn emoji(b: &mut Bencher) { |
| 110 | // To benchmark, download emoji-style.txt from https://www.unicode.org/emoji/charts/emoji-style.txt |
| 111 | let data_path = "bench_data/emoji-style.txt"; |
| 112 | let string = std::fs::read_to_string(data_path).unwrap_or_default(); |
| 113 | b.iter(|| test::black_box(UnicodeWidthStr::width(string.as_str()))); |
| 114 | } |
| 115 |