ANSI function benchmarks
Gábor Csárdi
2025-06-01
Source:vignettes/ansi-benchmark.Rmd
ansi-benchmark.Rmd
$output function (x, options) { if (class == “output” && output_asis(x, options)) return(x) hook.t(x, options[[paste0(“attr.”, class)]], options[[paste0(“class.”, class)]]) } <bytecode: 0x55c2e28dad60> <environment: 0x55c2e333a2d0>
Introduction
Often we can use the corresponding base R function as a baseline. We also compare to the fansi package, where it is possible.
Data
In cli the typical use case is short string scalars, but we run some benchmarks longer strings and string vectors as well.
ansi <- format_inline(
"{col_green(symbol$tick)} {.code print(x)} {.emph emphasised}"
)
plain <- ansi_strip(ansi)
ANSI functions
ansi_align()
bench::mark(
ansi = ansi_align(ansi, width = 20),
plain = ansi_align(plain, width = 20),
base = format(plain, width = 20),
check = FALSE
)
#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 ansi 46.9µs 50.2µs 19448. 99.3KB 18.8
#> 2 plain 46.1µs 49.5µs 19753. 0B 19.4
#> 3 base 11.4µs 12.3µs 79592. 48.4KB 15.9
bench::mark(
ansi = ansi_align(ansi, width = 20, align = "right"),
plain = ansi_align(plain, width = 20, align = "right"),
base = format(plain, width = 20, justify = "right"),
check = FALSE
)
#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 ansi 47.5µs 50.9µs 19162. 0B 20.9
#> 2 plain 47.9µs 51.1µs 18957. 0B 21.1
#> 3 base 13.2µs 14.3µs 68076. 0B 20.4
ansi_chartr()
bench::mark(
ansi = ansi_chartr("abc", "XYZ", ansi),
plain = ansi_chartr("abc", "XYZ", plain),
base = chartr("abc", "XYZ", plain),
check = FALSE
)
#> # A tibble: 3 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 ansi 110.88µs 117.23µs 8339. 75.07KB 14.5
#> 2 plain 88.31µs 92.93µs 10491. 8.73KB 14.5
#> 3 base 1.85µs 1.97µs 492654. 0B 49.3
ansi_columns()
bench::mark(
ansi = ansi_columns(vec_ansi6, width = 120),
plain = ansi_columns(vec_plain6, width = 120),
check = FALSE
)
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 ansi 330µs 355µs 2793. 33.17KB 18.9
#> 2 plain 329µs 350µs 2834. 1.09KB 19.0
ansi_has_any()
bench::mark(
cli_ansi = ansi_has_any(ansi),
fansi_ansi = has_sgr(ansi),
cli_plain = ansi_has_any(plain),
fansi_plain = has_sgr(plain),
cli_vec_ansi = ansi_has_any(vec_ansi),
fansi_vec_ansi = has_sgr(vec_ansi),
cli_vec_plain = ansi_has_any(vec_plain),
fansi_vec_plain = has_sgr(vec_plain),
cli_txt_ansi = ansi_has_any(txt_ansi),
fansi_txt_ansi = has_sgr(txt_ansi),
cli_txt_plain = ansi_has_any(txt_plain),
fansi_txt_plain = has_sgr(vec_plain),
check = FALSE
)
#> # A tibble: 12 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 5.9µs 6.4µs 151592. 9.2KB 30.3
#> 2 fansi_ansi 30.87µs 33.01µs 29580. 4.18KB 23.7
#> 3 cli_plain 5.95µs 6.37µs 152900. 0B 30.6
#> 4 fansi_plain 30.24µs 32.44µs 30069. 688B 24.1
#> 5 cli_vec_ansi 7.35µs 7.64µs 127876. 448B 25.6
#> 6 fansi_vec_ansi 39.27µs 41.11µs 23766. 5.02KB 19.0
#> 7 cli_vec_plain 7.95µs 8.29µs 118138. 448B 11.8
#> 8 fansi_vec_plain 37.87µs 39.84µs 24477. 5.02KB 22.0
#> 9 cli_txt_ansi 5.78µs 6.19µs 158224. 0B 15.8
#> 10 fansi_txt_ansi 30.41µs 31.96µs 30498. 688B 27.5
#> 11 cli_txt_plain 6.76µs 7.06µs 135245. 0B 13.5
#> 12 fansi_txt_plain 37.55µs 39.82µs 24523. 5.02KB 19.6
ansi_html()
This is typically used with longer text.
bench::mark(
cli = ansi_html(txt_ansi),
fansi = sgr_to_html(txt_ansi, classes = TRUE),
check = FALSE
)
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli 59µs 60.5µs 16175. 22.7KB 8.15
#> 2 fansi 115µs 118.3µs 8296. 55.3KB 8.16
ansi_nchar()
bench::mark(
cli_ansi = ansi_nchar(ansi),
fansi_ansi = nchar_sgr(ansi),
base_ansi = nchar(ansi),
cli_plain = ansi_nchar(plain),
fansi_plain = nchar_sgr(plain),
base_plain = nchar(plain),
cli_vec_ansi = ansi_nchar(vec_ansi),
fansi_vec_ansi = nchar_sgr(vec_ansi),
base_vec_ansi = nchar(vec_ansi),
cli_vec_plain = ansi_nchar(vec_plain),
fansi_vec_plain = nchar_sgr(vec_plain),
base_vec_plain = nchar(vec_plain),
cli_txt_ansi = ansi_nchar(txt_ansi),
fansi_txt_ansi = nchar_sgr(txt_ansi),
base_txt_ansi = nchar(txt_ansi),
cli_txt_plain = ansi_nchar(txt_plain),
fansi_txt_plain = nchar_sgr(txt_plain),
base_txt_plain = nchar(txt_plain),
check = FALSE
)
#> # A tibble: 18 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 6.7µs 7.26µs 134029. 0B 26.8
#> 2 fansi_ansi 91.7µs 96.2µs 10148. 38.83KB 16.6
#> 3 base_ansi 901.05ns 942.15ns 1016317. 0B 0
#> 4 cli_plain 6.63µs 7.08µs 136870. 0B 27.4
#> 5 fansi_plain 91.25µs 95.64µs 10203. 688B 16.6
#> 6 base_plain 831.09ns 872.07ns 1096695. 0B 0
#> 7 cli_vec_ansi 28.59µs 29.3µs 33601. 448B 6.72
#> 8 fansi_vec_ansi 111.57µs 116µs 8419. 5.02KB 12.4
#> 9 base_vec_ansi 16.02µs 16.09µs 61339. 448B 6.13
#> 10 cli_vec_plain 26.69µs 27.3µs 36053. 448B 3.61
#> 11 fansi_vec_plain 102.54µs 106.49µs 9160. 5.02KB 16.7
#> 12 base_vec_plain 9.52µs 9.58µs 102696. 448B 0
#> 13 cli_txt_ansi 28µs 28.71µs 34300. 0B 6.86
#> 14 fansi_txt_ansi 103.91µs 108.34µs 9016. 688B 14.5
#> 15 base_txt_ansi 15.65µs 15.7µs 62775. 0B 0
#> 16 cli_txt_plain 26.15µs 26.82µs 36376. 0B 7.28
#> 17 fansi_txt_plain 94.11µs 98.92µs 9844. 688B 14.5
#> 18 base_txt_plain 9.19µs 9.25µs 105947. 0B 10.6
bench::mark(
cli_ansi = ansi_nchar(ansi, type = "width"),
fansi_ansi = nchar_sgr(ansi, type = "width"),
base_ansi = nchar(ansi, "width"),
cli_plain = ansi_nchar(plain, type = "width"),
fansi_plain = nchar_sgr(plain, type = "width"),
base_plain = nchar(plain, "width"),
cli_vec_ansi = ansi_nchar(vec_ansi, type = "width"),
fansi_vec_ansi = nchar_sgr(vec_ansi, type = "width"),
base_vec_ansi = nchar(vec_ansi, "width"),
cli_vec_plain = ansi_nchar(vec_plain, type = "width"),
fansi_vec_plain = nchar_sgr(vec_plain, type = "width"),
base_vec_plain = nchar(vec_plain, "width"),
cli_txt_ansi = ansi_nchar(txt_ansi, type = "width"),
fansi_txt_ansi = nchar_sgr(txt_ansi, type = "width"),
base_txt_ansi = nchar(txt_ansi, "width"),
cli_txt_plain = ansi_nchar(txt_plain, type = "width"),
fansi_txt_plain = nchar_sgr(txt_plain, type = "width"),
base_txt_plain = nchar(txt_plain, type = "width"),
check = FALSE
)
#> # A tibble: 18 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 8.46µs 9.01µs 108232. 0B 32.5
#> 2 fansi_ansi 92.69µs 96.74µs 10068. 688B 16.5
#> 3 base_ansi 1.21µs 1.26µs 757889. 0B 0
#> 4 cli_plain 8.32µs 8.89µs 109960. 0B 22.0
#> 5 fansi_plain 92.15µs 95.82µs 10180. 688B 16.5
#> 6 base_plain 971.02ns 1.02µs 931423. 0B 0
#> 7 cli_vec_ansi 34.84µs 35.54µs 27628. 448B 8.29
#> 8 fansi_vec_ansi 120.01µs 123.66µs 7894. 5.02KB 12.4
#> 9 base_vec_ansi 41.37µs 41.52µs 23829. 448B 0
#> 10 cli_vec_plain 33.28µs 34.02µs 28792. 448B 5.76
#> 11 fansi_vec_plain 110.25µs 114.35µs 8536. 5.02KB 12.4
#> 12 base_vec_plain 21.75µs 21.94µs 45011. 448B 0
#> 13 cli_txt_ansi 34.91µs 35.55µs 27702. 0B 8.31
#> 14 fansi_txt_ansi 111.24µs 115.25µs 8489. 688B 12.3
#> 15 base_txt_ansi 44.15µs 44.45µs 22157. 0B 2.22
#> 16 cli_txt_plain 32.94µs 33.59µs 29310. 0B 5.86
#> 17 fansi_txt_plain 101.11µs 105.51µs 9255. 688B 14.5
#> 18 base_txt_plain 23.22µs 23.95µs 41311. 0B 4.13
ansi_simplify()
Nothing to compare here.
bench::mark(
cli_ansi = ansi_simplify(ansi),
cli_plain = ansi_simplify(plain),
cli_vec_ansi = ansi_simplify(vec_ansi),
cli_vec_plain = ansi_simplify(vec_plain),
cli_txt_ansi = ansi_simplify(txt_ansi),
cli_txt_plain = ansi_simplify(txt_plain),
check = FALSE
)
#> # A tibble: 6 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 6.78µs 7.28µs 133824. 0B 26.8
#> 2 cli_plain 6.36µs 6.7µs 145672. 0B 14.6
#> 3 cli_vec_ansi 33.02µs 33.97µs 29021. 848B 5.81
#> 4 cli_vec_plain 10.26µs 10.87µs 90063. 848B 9.01
#> 5 cli_txt_ansi 31.93µs 32.61µs 30185. 0B 6.04
#> 6 cli_txt_plain 7.22µs 7.67µs 127437. 0B 25.5
ansi_strip()
bench::mark(
cli_ansi = ansi_strip(ansi),
fansi_ansi = strip_sgr(ansi),
cli_plain = ansi_strip(plain),
fansi_plain = strip_sgr(plain),
cli_vec_ansi = ansi_strip(vec_ansi),
fansi_vec_ansi = strip_sgr(vec_ansi),
cli_vec_plain = ansi_strip(vec_plain),
fansi_vec_plain = strip_sgr(vec_plain),
cli_txt_ansi = ansi_strip(txt_ansi),
fansi_txt_ansi = strip_sgr(txt_ansi),
cli_txt_plain = ansi_strip(txt_plain),
fansi_txt_plain = strip_sgr(txt_plain),
check = FALSE
)
#> # A tibble: 12 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 25.8µs 27.2µs 35979. 0B 28.8
#> 2 fansi_ansi 28.5µs 30.1µs 32382. 7.24KB 25.9
#> 3 cli_plain 25.3µs 26.4µs 37018. 0B 29.6
#> 4 fansi_plain 28µs 29.6µs 33044. 688B 23.1
#> 5 cli_vec_ansi 35µs 36.4µs 26887. 848B 21.5
#> 6 fansi_vec_ansi 53.7µs 55.9µs 17493. 5.41KB 14.6
#> 7 cli_vec_plain 28.3µs 30µs 32525. 848B 26.0
#> 8 fansi_vec_plain 36.3µs 38.1µs 25629. 4.59KB 18.0
#> 9 cli_txt_ansi 34.7µs 36.4µs 26921. 0B 21.6
#> 10 fansi_txt_ansi 44.6µs 46.7µs 20929. 5.12KB 16.9
#> 11 cli_txt_plain 26.5µs 27.9µs 34981. 0B 28.0
#> 12 fansi_txt_plain 28.9µs 30.3µs 32241. 688B 25.8
ansi_strsplit()
bench::mark(
cli_ansi = ansi_strsplit(ansi, "i"),
fansi_ansi = strsplit_sgr(ansi, "i"),
base_ansi = strsplit(ansi, "i"),
cli_plain = ansi_strsplit(plain, "i"),
fansi_plain = strsplit_sgr(plain, "i"),
base_plain = strsplit(plain, "i"),
cli_vec_ansi = ansi_strsplit(vec_ansi, "i"),
fansi_vec_ansi = strsplit_sgr(vec_ansi, "i"),
base_vec_ansi = strsplit(vec_ansi, "i"),
cli_vec_plain = ansi_strsplit(vec_plain, "i"),
fansi_vec_plain = strsplit_sgr(vec_plain, "i"),
base_vec_plain = strsplit(vec_plain, "i"),
cli_txt_ansi = ansi_strsplit(txt_ansi, "i"),
fansi_txt_ansi = strsplit_sgr(txt_ansi, "i"),
base_txt_ansi = strsplit(txt_ansi, "i"),
cli_txt_plain = ansi_strsplit(txt_plain, "i"),
fansi_txt_plain = strsplit_sgr(txt_plain, "i"),
base_txt_plain = strsplit(txt_plain, "i"),
check = FALSE
)
#> # A tibble: 18 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 162.99µs 169.8µs 5754. 104.34KB 18.9
#> 2 fansi_ansi 125.75µs 131.58µs 7425. 106.35KB 21.1
#> 3 base_ansi 4.16µs 4.51µs 217102. 224B 0
#> 4 cli_plain 161.38µs 168.33µs 5798. 8.09KB 18.8
#> 5 fansi_plain 123.89µs 129.49µs 7543. 9.62KB 21.0
#> 6 base_plain 3.65µs 3.9µs 250033. 0B 25.0
#> 7 cli_vec_ansi 7.43ms 7.54ms 132. 823.77KB 24.9
#> 8 fansi_vec_ansi 1.02ms 1.06ms 911. 846.81KB 19.3
#> 9 base_vec_ansi 156.41µs 161.36µs 6098. 22.7KB 2.03
#> 10 cli_vec_plain 7.42ms 7.53ms 132. 823.77KB 28.6
#> 11 fansi_vec_plain 965.81µs 1ms 983. 845.98KB 19.5
#> 12 base_vec_plain 105.45µs 110.86µs 8837. 848B 4.05
#> 13 cli_txt_ansi 3.41ms 3.44ms 290. 63.6KB 0
#> 14 fansi_txt_ansi 1.54ms 1.56ms 638. 35.05KB 2.02
#> 15 base_txt_ansi 136.77µs 146.13µs 6626. 18.47KB 2.03
#> 16 cli_txt_plain 2.38ms 2.4ms 414. 63.6KB 0
#> 17 fansi_txt_plain 516.98µs 545.34µs 1824. 30.6KB 6.72
#> 18 base_txt_plain 86.9µs 89.43µs 10972. 11.05KB 2.01
ansi_strtrim()
bench::mark(
cli_ansi = ansi_strtrim(ansi, 10),
fansi_ansi = strtrim_sgr(ansi, 10),
base_ansi = strtrim(ansi, 10),
cli_plain = ansi_strtrim(plain, 10),
fansi_plain = strtrim_sgr(plain, 10),
base_plain = strtrim(plain, 10),
cli_vec_ansi = ansi_strtrim(vec_ansi, 10),
fansi_vec_ansi = strtrim_sgr(vec_ansi, 10),
base_vec_ansi = strtrim(vec_ansi, 10),
cli_vec_plain = ansi_strtrim(vec_plain, 10),
fansi_vec_plain = strtrim_sgr(vec_plain, 10),
base_vec_plain = strtrim(vec_plain, 10),
cli_txt_ansi = ansi_strtrim(txt_ansi, 10),
fansi_txt_ansi = strtrim_sgr(txt_ansi, 10),
base_txt_ansi = strtrim(txt_ansi, 10),
cli_txt_plain = ansi_strtrim(txt_plain, 10),
fansi_txt_plain = strtrim_sgr(txt_plain, 10),
base_txt_plain = strtrim(txt_plain, 10),
check = FALSE
)
#> # A tibble: 18 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 145.63µs 152.59µs 6414. 33.84KB 23.0
#> 2 fansi_ansi 53.75µs 56.73µs 17173. 31.43KB 23.5
#> 3 base_ansi 1.09µs 1.14µs 835431. 4.2KB 0
#> 4 cli_plain 143.43µs 149.76µs 6529. 0B 25.3
#> 5 fansi_plain 52.84µs 55.93µs 17462. 872B 23.1
#> 6 base_plain 1µs 1.05µs 902903. 0B 0
#> 7 cli_vec_ansi 273.8µs 284.97µs 3360. 16.73KB 12.4
#> 8 fansi_vec_ansi 122.72µs 126.8µs 7693. 5.59KB 12.4
#> 9 base_vec_ansi 35.94µs 36.28µs 27245. 848B 0
#> 10 cli_vec_plain 229.24µs 237.44µs 4138. 16.73KB 14.7
#> 11 fansi_vec_plain 119.97µs 123.58µs 7930. 5.59KB 12.4
#> 12 base_vec_plain 30.05µs 30.77µs 31898. 848B 0
#> 13 cli_txt_ansi 154.61µs 161.56µs 6069. 0B 23.1
#> 14 fansi_txt_ansi 52.94µs 56.24µs 17354. 872B 23.1
#> 15 base_txt_ansi 1.13µs 1.17µs 814429. 0B 0
#> 16 cli_txt_plain 145.92µs 151.59µs 6463. 0B 25.3
#> 17 fansi_txt_plain 53.39µs 56.45µs 17299. 872B 23.2
#> 18 base_txt_plain 1.04µs 1.08µs 885174. 0B 0
ansi_strwrap()
This function is most useful for longer text, but it is often called for short text in cli, so it makes sense to benchmark that as well.
bench::mark(
cli_ansi = ansi_strwrap(ansi, 30),
fansi_ansi = strwrap_sgr(ansi, 30),
base_ansi = strwrap(ansi, 30),
cli_plain = ansi_strwrap(plain, 30),
fansi_plain = strwrap_sgr(plain, 30),
base_plain = strwrap(plain, 30),
cli_vec_ansi = ansi_strwrap(vec_ansi, 30),
fansi_vec_ansi = strwrap_sgr(vec_ansi, 30),
base_vec_ansi = strwrap(vec_ansi, 30),
cli_vec_plain = ansi_strwrap(vec_plain, 30),
fansi_vec_plain = strwrap_sgr(vec_plain, 30),
base_vec_plain = strwrap(vec_plain, 30),
cli_txt_ansi = ansi_strwrap(txt_ansi, 30),
fansi_txt_ansi = strwrap_sgr(txt_ansi, 30),
base_txt_ansi = strwrap(txt_ansi, 30),
cli_txt_plain = ansi_strwrap(txt_plain, 30),
fansi_txt_plain = strwrap_sgr(txt_plain, 30),
base_txt_plain = strwrap(txt_plain, 30),
check = FALSE
)
#> # A tibble: 18 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 401.09µs 422.35µs 2351. 0B 21.6
#> 2 fansi_ansi 96.31µs 101.31µs 9667. 97.33KB 20.9
#> 3 base_ansi 38.51µs 40.58µs 23828. 0B 21.5
#> 4 cli_plain 272.59µs 285.33µs 3452. 0B 18.8
#> 5 fansi_plain 95.49µs 100.4µs 9745. 872B 23.1
#> 6 base_plain 32.09µs 33.66µs 28952. 0B 20.3
#> 7 cli_vec_ansi 42.17ms 42.46ms 23.5 2.48KB 118.
#> 8 fansi_vec_ansi 242.05µs 251.06µs 3931. 7.25KB 10.3
#> 9 base_vec_ansi 2.22ms 2.27ms 440. 48.18KB 26.5
#> 10 cli_vec_plain 28.68ms 28.88ms 34.6 2.48KB 38.9
#> 11 fansi_vec_plain 201.55µs 209.89µs 4677. 6.42KB 14.6
#> 12 base_vec_plain 1.61ms 1.66ms 599. 47.4KB 21.8
#> 13 cli_txt_ansi 23.88ms 23.99ms 41.7 507.59KB 13.0
#> 14 fansi_txt_ansi 232.61µs 241.12µs 4084. 6.77KB 10.3
#> 15 base_txt_ansi 1.25ms 1.28ms 766. 582.06KB 20.3
#> 16 cli_txt_plain 1.26ms 1.29ms 767. 369.84KB 17.5
#> 17 fansi_txt_plain 183.5µs 188.58µs 5219. 2.51KB 12.3
#> 18 base_txt_plain 839.46µs 863.89µs 1149. 367.31KB 17.6
ansi_substr()
bench::mark(
cli_ansi = ansi_substr(ansi, 2, 10),
fansi_ansi = substr_sgr(ansi, 2, 10),
base_ansi = substr(ansi, 2, 10),
cli_plain = ansi_substr(plain, 2, 10),
fansi_plain = substr_sgr(plain, 2, 10),
base_plain = substr(plain, 2, 10),
cli_vec_ansi = ansi_substr(vec_ansi, 2, 10),
fansi_vec_ansi = substr_sgr(vec_ansi, 2, 10),
base_vec_ansi = substr(vec_ansi, 2, 10),
cli_vec_plain = ansi_substr(vec_plain, 2, 10),
fansi_vec_plain = substr_sgr(vec_plain, 2, 10),
base_vec_plain = substr(vec_plain, 2, 10),
cli_txt_ansi = ansi_substr(txt_ansi, 2, 10),
fansi_txt_ansi = substr_sgr(txt_ansi, 2, 10),
base_txt_ansi = substr(txt_ansi, 2, 10),
cli_txt_plain = ansi_substr(txt_plain, 2, 10),
fansi_txt_plain = substr_sgr(txt_plain, 2, 10),
base_txt_plain = substr(txt_plain, 2, 10),
check = FALSE
)
#> # A tibble: 18 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 6.87µs 7.26µs 134712. 24.83KB 26.9
#> 2 fansi_ansi 77.2µs 81.09µs 12045. 28.48KB 21.1
#> 3 base_ansi 1.04µs 1.08µs 878667. 0B 87.9
#> 4 cli_plain 6.85µs 7.29µs 133544. 0B 26.7
#> 5 fansi_plain 76.12µs 80.2µs 12162. 1.98KB 21.0
#> 6 base_plain 972.07ns 1.05µs 906806. 0B 90.7
#> 7 cli_vec_ansi 27.09µs 27.91µs 35285. 1.7KB 7.06
#> 8 fansi_vec_ansi 112.75µs 116.7µs 8330. 8.86KB 14.6
#> 9 base_vec_ansi 6.02µs 6.14µs 159418. 848B 0
#> 10 cli_vec_plain 22.94µs 24µs 40922. 1.7KB 12.3
#> 11 fansi_vec_plain 106.49µs 111.1µs 8798. 8.86KB 14.7
#> 12 base_vec_plain 5.8µs 5.91µs 163992. 848B 16.4
#> 13 cli_txt_ansi 6.9µs 7.35µs 132558. 0B 26.5
#> 14 fansi_txt_ansi 75.98µs 79.96µs 12203. 1.98KB 21.0
#> 15 base_txt_ansi 5.17µs 5.25µs 186772. 0B 18.7
#> 16 cli_txt_plain 7.45µs 7.93µs 123014. 0B 24.6
#> 17 fansi_txt_plain 76.15µs 80.02µs 12131. 1.98KB 21.0
#> 18 base_txt_plain 3.38µs 3.45µs 282767. 0B 0
ansi_tolower()
, ansi_toupper()
bench::mark(
cli_ansi = ansi_tolower(ansi),
base_ansi = tolower(ansi),
cli_plain = ansi_tolower(plain),
base_plain = tolower(plain),
cli_vec_ansi = ansi_tolower(vec_ansi),
base_vec_ansi = tolower(vec_ansi),
cli_vec_plain = ansi_tolower(vec_plain),
base_vec_plain = tolower(vec_plain),
cli_txt_ansi = ansi_tolower(txt_ansi),
base_txt_ansi = tolower(txt_ansi),
cli_txt_plain = ansi_tolower(txt_plain),
base_txt_plain = tolower(txt_plain),
check = FALSE
)
#> # A tibble: 12 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 105.41µs 109.97µs 8851. 11.88KB 16.6
#> 2 base_ansi 1.33µs 1.38µs 705647. 0B 0
#> 3 cli_plain 84.8µs 88.71µs 10964. 8.73KB 14.5
#> 4 base_plain 1.02µs 1.06µs 918151. 0B 0
#> 5 cli_vec_ansi 4.02ms 4.11ms 243. 838.77KB 31.0
#> 6 base_vec_ansi 74.41µs 74.8µs 13234. 848B 0
#> 7 cli_vec_plain 2.26ms 2.32ms 429. 816.9KB 28.4
#> 8 base_vec_plain 43.91µs 44.27µs 22336. 848B 0
#> 9 cli_txt_ansi 13.47ms 13.6ms 73.5 114.42KB 6.49
#> 10 base_txt_ansi 75.91µs 76.19µs 12990. 0B 0
#> 11 cli_txt_plain 269.38µs 277.5µs 3550. 18.16KB 6.10
#> 12 base_txt_plain 42.25µs 43.71µs 22848. 0B 0
ansi_trimws()
bench::mark(
cli_ansi = ansi_trimws(ansi),
base_ansi = trimws(ansi),
cli_plain = ansi_trimws(plain),
base_plain = trimws(plain),
cli_vec_ansi = ansi_trimws(vec_ansi),
base_vec_ansi = trimws(vec_ansi),
cli_vec_plain = ansi_trimws(vec_plain),
base_vec_plain = trimws(vec_plain),
cli_txt_ansi = ansi_trimws(txt_ansi),
base_txt_ansi = trimws(txt_ansi),
cli_txt_plain = ansi_trimws(txt_plain),
base_txt_plain = trimws(txt_plain),
check = FALSE
)
#> # A tibble: 12 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli_ansi 107.2µs 112.5µs 8637. 0B 23.0
#> 2 base_ansi 16.4µs 17.4µs 56109. 0B 22.5
#> 3 cli_plain 106µs 111.1µs 8785. 0B 23.0
#> 4 base_plain 16.3µs 17.3µs 56524. 0B 22.6
#> 5 cli_vec_ansi 202.8µs 211.9µs 4634. 7.2KB 12.4
#> 6 base_vec_ansi 55.1µs 63.5µs 15492. 1.66KB 6.10
#> 7 cli_vec_plain 189.9µs 199.3µs 4928. 7.2KB 12.4
#> 8 base_vec_plain 49.4µs 56.6µs 17342. 1.66KB 6.10
#> 9 cli_txt_ansi 177µs 183.4µs 5344. 0B 14.5
#> 10 base_txt_ansi 37.9µs 39.1µs 25018. 0B 7.51
#> 11 cli_txt_plain 158.9µs 166.7µs 5866. 0B 16.7
#> 12 base_txt_plain 33.4µs 34.5µs 28320. 0B 11.3
UTF-8 functions
utf8_nchar()
bench::mark(
cli = utf8_nchar(uni, type = "chars"),
base = nchar(uni, "chars"),
cli_vec = utf8_nchar(vec_uni, type = "chars"),
base_vec = nchar(vec_uni, "chars"),
cli_txt = utf8_nchar(txt_uni, type = "chars"),
base_txt = nchar(txt_uni, "chars"),
check = FALSE
)
#> # A tibble: 6 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli 8.14µs 8.69µs 112230. 0B 22.5
#> 2 base 881.03ns 932.02ns 1003496. 0B 0
#> 3 cli_vec 23.01µs 23.69µs 41394. 448B 12.4
#> 4 base_vec 11.59µs 11.89µs 82949. 448B 0
#> 5 cli_txt 23.17µs 23.81µs 41131. 0B 8.23
#> 6 base_txt 12.41µs 12.71µs 76942. 0B 7.69
bench::mark(
cli = utf8_nchar(uni, type = "width"),
base = nchar(uni, "width"),
cli_vec = utf8_nchar(vec_uni, type = "width"),
base_vec = nchar(vec_uni, "width"),
cli_txt = utf8_nchar(txt_uni, type = "width"),
base_txt = nchar(txt_uni, "width"),
check = FALSE
)
#> # A tibble: 6 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli 8.07µs 8.72µs 111419. 0B 22.3
#> 2 base 1.33µs 1.38µs 692855. 0B 0
#> 3 cli_vec 28.52µs 29.3µs 33501. 448B 10.1
#> 4 base_vec 51.05µs 51.65µs 19135. 448B 0
#> 5 cli_txt 28.91µs 29.68µs 33104. 0B 6.62
#> 6 base_txt 87.75µs 88.62µs 11170. 0B 0
bench::mark(
cli = utf8_nchar(uni, type = "codepoints"),
base = nchar(uni, "chars"),
cli_vec = utf8_nchar(vec_uni, type = "codepoints"),
base_vec = nchar(vec_uni, "chars"),
cli_txt = utf8_nchar(txt_uni, type = "codepoints"),
base_txt = nchar(txt_uni, "chars"),
check = FALSE
)
#> # A tibble: 6 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli 8.63µs 9.18µs 106147. 0B 21.2
#> 2 base 891.04ns 932.02ns 1017290. 0B 0
#> 3 cli_vec 19.58µs 20.27µs 48376. 448B 14.5
#> 4 base_vec 11.6µs 11.92µs 82715. 448B 0
#> 5 cli_txt 20.11µs 20.87µs 46945. 0B 14.1
#> 6 base_txt 12.41µs 12.71µs 77904. 0B 0
utf8_substr()
bench::mark(
cli = utf8_substr(uni, 2, 10),
base = substr(uni, 2, 10),
cli_vec = utf8_substr(vec_uni, 2, 10),
base_vec = substr(vec_uni, 2, 10),
cli_txt = utf8_substr(txt_uni, 2, 10),
base_txt = substr(txt_uni, 2, 10),
check = FALSE
)
#> # A tibble: 6 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 cli 6.31µs 6.82µs 142010. 22.1KB 28.4
#> 2 base 1.07µs 1.12µs 845319. 0B 84.5
#> 3 cli_vec 28.87µs 29.66µs 33182. 1.7KB 6.64
#> 4 base_vec 7.91µs 8.39µs 117686. 848B 0
#> 5 cli_txt 6.27µs 6.73µs 144030. 0B 43.2
#> 6 base_txt 5.48µs 5.54µs 176832. 0B 0
Session info
sessioninfo::session_info()
#> ─ Session info ──────────────────────────────────────────────────────
#> setting value
#> version R version 4.5.0 (2025-04-11)
#> os Ubuntu 24.04.2 LTS
#> system x86_64, linux-gnu
#> ui X11
#> language en
#> collate C.UTF-8
#> ctype C.UTF-8
#> tz UTC
#> date 2025-06-01
#> pandoc 3.1.11 @ /opt/hostedtoolcache/pandoc/3.1.11/x64/ (via rmarkdown)
#> quarto NA
#>
#> ─ Packages ──────────────────────────────────────────────────────────
#> package * version date (UTC) lib source
#> bench 1.1.4 2025-01-16 [1] RSPM
#> bslib 0.9.0 2025-01-30 [1] RSPM
#> cachem 1.1.0 2024-05-16 [1] RSPM
#> cli * 3.6.5.9000 2025-06-01 [1] local
#> codetools 0.2-20 2024-03-31 [3] CRAN (R 4.5.0)
#> desc 1.4.3 2023-12-10 [1] RSPM
#> digest 0.6.37 2024-08-19 [1] RSPM
#> evaluate 1.0.3 2025-01-10 [1] RSPM
#> fansi * 1.0.6 2023-12-08 [1] RSPM
#> fastmap 1.2.0 2024-05-15 [1] RSPM
#> fs 1.6.6 2025-04-12 [1] RSPM
#> glue 1.8.0 2024-09-30 [1] RSPM
#> htmltools 0.5.8.1 2024-04-04 [1] RSPM
#> htmlwidgets 1.6.4 2023-12-06 [1] RSPM
#> jquerylib 0.1.4 2021-04-26 [1] RSPM
#> jsonlite 2.0.0 2025-03-27 [1] RSPM
#> knitr 1.50 2025-03-16 [1] RSPM
#> lifecycle 1.0.4 2023-11-07 [1] RSPM
#> magrittr 2.0.3 2022-03-30 [1] RSPM
#> pillar 1.10.2 2025-04-05 [1] RSPM
#> pkgconfig 2.0.3 2019-09-22 [1] RSPM
#> pkgdown 2.1.3 2025-05-25 [1] any (@2.1.3)
#> profmem 0.7.0 2025-05-02 [1] RSPM
#> R6 2.6.1 2025-02-15 [1] RSPM
#> ragg 1.4.0 2025-04-10 [1] RSPM
#> rlang 1.1.6 2025-04-11 [1] RSPM
#> rmarkdown 2.29 2024-11-04 [1] RSPM
#> sass 0.4.10 2025-04-11 [1] RSPM
#> sessioninfo 1.2.3 2025-02-05 [1] RSPM
#> systemfonts 1.2.3 2025-04-30 [1] RSPM
#> textshaping 1.0.1 2025-05-01 [1] RSPM
#> tibble 3.2.1 2023-03-20 [1] RSPM
#> utf8 1.2.5 2025-05-01 [1] RSPM
#> vctrs 0.6.5 2023-12-01 [1] RSPM
#> xfun 0.52 2025-04-02 [1] RSPM
#> yaml 2.3.10 2024-07-26 [1] RSPM
#>
#> [1] /home/runner/work/_temp/Library
#> [2] /opt/R/4.5.0/lib/R/site-library
#> [3] /opt/R/4.5.0/lib/R/library
#> * ── Packages attached to the search path.
#>
#> ─────────────────────────────────────────────────────────────────────