ANSI function benchmarks
Gábor Csárdi
2025-08-15
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: 0x55dd16d75940> <environment: 0x55dd177d6c50>
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 45.7µs 49.5µs 19549. 99.3KB 18.9
#> 2 plain 46.5µs 49.8µs 19434. 0B 17.5
#> 3 base 11.5µs 12.8µs 76033. 48.4KB 22.8
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 48.2µs 51.8µs 18683. 0B 21.3
#> 2 plain 47.9µs 51.5µs 18764. 0B 21.4
#> 3 base 13.6µs 14.9µs 65582. 0B 19.7
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 112.91µs 120.47µs 8078. 75.07KB 14.6
#> 2 plain 89.17µs 95.06µs 10205. 8.73KB 14.6
#> 3 base 1.92µs 2.06µs 465839. 0B 0
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 344µs 370µs 2674. 33.17KB 19.1
#> 2 plain 344µs 370µs 2684. 1.09KB 19.2
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 150979. 9.2KB 30.2
#> 2 fansi_ansi 30.89µs 34.28µs 28295. 4.18KB 22.7
#> 3 cli_plain 5.93µs 6.44µs 150453. 0B 30.1
#> 4 fansi_plain 31.04µs 33.84µs 28655. 688B 22.9
#> 5 cli_vec_ansi 7.38µs 7.79µs 125449. 448B 25.1
#> 6 fansi_vec_ansi 39.9µs 42.03µs 23108. 5.02KB 18.5
#> 7 cli_vec_plain 7.89µs 8.29µs 118013. 448B 23.6
#> 8 fansi_vec_plain 38.81µs 40.68µs 23880. 5.02KB 19.1
#> 9 cli_txt_ansi 5.89µs 6.28µs 153486. 0B 30.7
#> 10 fansi_txt_ansi 30.93µs 32.82µs 29382. 688B 23.5
#> 11 cli_txt_plain 6.7µs 7.05µs 138388. 0B 27.7
#> 12 fansi_txt_plain 38.68µs 41.08µs 23650. 5.02KB 18.9
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 61.9µs 63.8µs 15384. 22.7KB 8.18
#> 2 fansi 115.1µs 118.5µs 8247. 55.3KB 8.20
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.88µs 7.41µs 130902. 0B 26.2
#> 2 fansi_ansi 93.36µs 98.22µs 9864. 38.83KB 14.6
#> 3 base_ansi 921.08ns 981.03ns 959418. 0B 96.0
#> 4 cli_plain 6.81µs 7.39µs 131384. 0B 26.3
#> 5 fansi_plain 92.32µs 97.83µs 9918. 688B 14.6
#> 6 base_plain 840.98ns 901.17ns 1030581. 0B 103.
#> 7 cli_vec_ansi 28.77µs 29.48µs 33312. 448B 3.33
#> 8 fansi_vec_ansi 113.83µs 119.09µs 8162. 5.02KB 14.7
#> 9 base_vec_ansi 17.26µs 17.35µs 56953. 448B 0
#> 10 cli_vec_plain 26.81µs 27.53µs 35615. 448B 7.12
#> 11 fansi_vec_plain 103.56µs 109.17µs 8878. 5.02KB 14.7
#> 12 base_vec_plain 10.2µs 10.28µs 95962. 448B 0
#> 13 cli_txt_ansi 28µs 28.76µs 34069. 0B 6.82
#> 14 fansi_txt_ansi 105.74µs 110.85µs 8755. 688B 14.6
#> 15 base_txt_ansi 16.91µs 16.99µs 58081. 0B 0
#> 16 cli_txt_plain 26.24µs 26.88µs 36540. 0B 7.31
#> 17 fansi_txt_plain 94.92µs 100.45µs 9654. 688B 14.6
#> 18 base_txt_plain 9.89µs 10.41µs 94360. 0B 0
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.59µs 9.19µs 105846. 0B 21.2
#> 2 fansi_ansi 94.3µs 99.72µs 9705. 688B 16.8
#> 3 base_ansi 1.23µs 1.29µs 739023. 0B 0
#> 4 cli_plain 8.58µs 9.21µs 105792. 0B 21.2
#> 5 fansi_plain 93.64µs 99.11µs 9773. 688B 18.1
#> 6 base_plain 1.01µs 1.07µs 892680. 0B 0
#> 7 cli_vec_ansi 35.05µs 35.82µs 27466. 448B 5.49
#> 8 fansi_vec_ansi 122.53µs 127.95µs 7594. 5.02KB 12.5
#> 9 base_vec_ansi 40.89µs 41.21µs 23956. 448B 0
#> 10 cli_vec_plain 33.26µs 34.05µs 28531. 448B 8.56
#> 11 fansi_vec_plain 113.35µs 118.61µs 8152. 5.02KB 12.5
#> 12 base_vec_plain 21.61µs 21.79µs 45326. 448B 0
#> 13 cli_txt_ansi 34.98µs 35.62µs 27579. 0B 8.28
#> 14 fansi_txt_ansi 115.03µs 120.56µs 7902. 688B 12.4
#> 15 base_txt_ansi 42.93µs 44.11µs 22422. 0B 0
#> 16 cli_txt_plain 32.9µs 33.62µs 29126. 0B 5.83
#> 17 fansi_txt_plain 105.37µs 110.69µs 8778. 688B 14.5
#> 18 base_txt_plain 23.19µs 23.72µs 41541. 0B 0
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.85µs 7.42µs 130993. 0B 13.1
#> 2 cli_plain 6.42µs 6.94µs 139934. 0B 28.0
#> 3 cli_vec_ansi 33.04µs 34.24µs 28681. 848B 5.74
#> 4 cli_vec_plain 10.36µs 10.97µs 88698. 848B 8.87
#> 5 cli_txt_ansi 32.72µs 33.65µs 28710. 0B 5.74
#> 6 cli_txt_plain 7.27µs 7.79µs 121180. 0B 24.2
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 26µs 27.6µs 34431. 0B 27.6
#> 2 fansi_ansi 28.6µs 30.5µs 31326. 7.24KB 25.1
#> 3 cli_plain 26µs 27.5µs 34427. 0B 27.6
#> 4 fansi_plain 28.4µs 30.2µs 32131. 688B 22.5
#> 5 cli_vec_ansi 35.2µs 37µs 25193. 848B 20.2
#> 6 fansi_vec_ansi 54.8µs 56.8µs 17169. 5.41KB 14.7
#> 7 cli_vec_plain 29.1µs 30.5µs 31861. 848B 25.5
#> 8 fansi_vec_plain 37µs 39.2µs 24819. 4.59KB 17.4
#> 9 cli_txt_ansi 35µs 36.5µs 26693. 0B 21.4
#> 10 fansi_txt_ansi 44.7µs 46.6µs 20928. 5.12KB 16.8
#> 11 cli_txt_plain 27µs 28.3µs 34149. 0B 27.3
#> 12 fansi_txt_plain 29.3µs 30.9µs 31352. 688B 25.1
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 167.19µs 176.51µs 5535. 104.34KB 19.0
#> 2 fansi_ansi 128.54µs 135.36µs 7208. 106.35KB 18.9
#> 3 base_ansi 4.13µs 4.44µs 220482. 224B 0
#> 4 cli_plain 167.16µs 175.91µs 5531. 8.09KB 18.9
#> 5 fansi_plain 128.15µs 135.92µs 7161. 9.62KB 19.0
#> 6 base_plain 3.71µs 3.93µs 247865. 0B 24.8
#> 7 cli_vec_ansi 7.68ms 7.83ms 124. 823.77KB 24.8
#> 8 fansi_vec_ansi 1.07ms 1.11ms 869. 846.81KB 17.3
#> 9 base_vec_ansi 158.72µs 165.26µs 5920. 22.7KB 4.09
#> 10 cli_vec_plain 7.68ms 7.85ms 123. 823.77KB 22.6
#> 11 fansi_vec_plain 1.03ms 1.07ms 913. 845.98KB 19.9
#> 12 base_vec_plain 109.31µs 112.2µs 8751. 848B 2.02
#> 13 cli_txt_ansi 3.45ms 3.5ms 285. 63.6KB 0
#> 14 fansi_txt_ansi 1.56ms 1.59ms 626. 35.05KB 2.02
#> 15 base_txt_ansi 138.69µs 146.92µs 6755. 18.47KB 2.02
#> 16 cli_txt_plain 2.38ms 2.42ms 413. 63.6KB 0
#> 17 fansi_txt_plain 529.26µs 549.79µs 1803. 30.6KB 6.16
#> 18 base_txt_plain 89.53µs 92.19µs 10677. 11.05KB 2.02
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 150.59µs 160.89µs 6014. 33.84KB 23.6
#> 2 fansi_ansi 55.09µs 58.68µs 16434. 31.43KB 21.1
#> 3 base_ansi 1.09µs 1.13µs 822731. 4.2KB 0
#> 4 cli_plain 147.34µs 157.32µs 6165. 0B 24.8
#> 5 fansi_plain 54.31µs 57.34µs 16919. 872B 21.1
#> 6 base_plain 1.01µs 1.06µs 894861. 0B 0
#> 7 cli_vec_ansi 281.63µs 291.67µs 3379. 16.73KB 12.5
#> 8 fansi_vec_ansi 122.65µs 127.19µs 7691. 5.59KB 12.5
#> 9 base_vec_ansi 36.29µs 37.74µs 26396. 848B 0
#> 10 cli_vec_plain 233.06µs 242.89µs 4046. 16.73KB 14.7
#> 11 fansi_vec_plain 119.63µs 124.25µs 7874. 5.59KB 12.5
#> 12 base_vec_plain 31.15µs 31.62µs 31257. 848B 0
#> 13 cli_txt_ansi 158.99µs 166.59µs 5863. 0B 21.2
#> 14 fansi_txt_ansi 54.98µs 58.68µs 16578. 872B 23.4
#> 15 base_txt_ansi 1.12µs 1.17µs 808569. 0B 0
#> 16 cli_txt_plain 150.37µs 158.55µs 6146. 0B 23.5
#> 17 fansi_txt_plain 54.95µs 58.52µs 16627. 872B 21.2
#> 18 base_txt_plain 1.03µs 1.08µs 867024. 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 413.41µs 440.44µs 2255. 0B 19.1
#> 2 fansi_ansi 99.44µs 106.33µs 9138. 97.33KB 21.3
#> 3 base_ansi 39.61µs 42µs 22931. 0B 18.4
#> 4 cli_plain 279.95µs 295.93µs 3328. 0B 21.0
#> 5 fansi_plain 96.8µs 103.26µs 9438. 872B 19.5
#> 6 base_plain 32.6µs 34.36µs 28142. 0B 19.7
#> 7 cli_vec_ansi 43.58ms 43.58ms 22.9 2.48KB 229.
#> 8 fansi_vec_ansi 245.73µs 254.81µs 3860. 7.25KB 10.3
#> 9 base_vec_ansi 2.32ms 2.38ms 419. 48.18KB 22.3
#> 10 cli_vec_plain 29.55ms 29.72ms 33.6 2.48KB 56.1
#> 11 fansi_vec_plain 204.85µs 213.97µs 4593. 6.42KB 12.5
#> 12 base_vec_plain 1.68ms 1.72ms 577. 47.4KB 22.0
#> 13 cli_txt_ansi 25.92ms 26.05ms 38.3 507.59KB 13.7
#> 14 fansi_txt_ansi 233.66µs 243.59µs 4051. 6.77KB 8.20
#> 15 base_txt_ansi 1.27ms 1.31ms 750. 582.06KB 20.7
#> 16 cli_txt_plain 1.3ms 1.34ms 735. 369.84KB 15.4
#> 17 fansi_txt_plain 184.72µs 192.8µs 5057. 2.51KB 12.5
#> 18 base_txt_plain 869.72µs 905.42µs 1082. 367.31KB 17.9
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 7.04µs 7.71µs 125952. 24.83KB 25.2
#> 2 fansi_ansi 79.38µs 84.66µs 11425. 28.48KB 19.0
#> 3 base_ansi 1.06µs 1.13µs 824443. 0B 82.5
#> 4 cli_plain 6.98µs 7.57µs 128263. 0B 25.7
#> 5 fansi_plain 78.99µs 83.58µs 11610. 1.98KB 21.9
#> 6 base_plain 1.02µs 1.07µs 893793. 0B 0
#> 7 cli_vec_ansi 28.1µs 28.87µs 33991. 1.7KB 6.80
#> 8 fansi_vec_ansi 113.65µs 118.64µs 8231. 8.86KB 14.7
#> 9 base_vec_ansi 6.1µs 6.32µs 155370. 848B 0
#> 10 cli_vec_plain 23.17µs 24.52µs 40113. 1.7KB 12.0
#> 11 fansi_vec_plain 108.98µs 113.09µs 8632. 8.86KB 14.7
#> 12 base_vec_plain 5.91µs 6.02µs 163364. 848B 0
#> 13 cli_txt_ansi 6.94µs 7.51µs 128582. 0B 38.6
#> 14 fansi_txt_ansi 78.69µs 83.26µs 11696. 1.98KB 19.0
#> 15 base_txt_ansi 6.5µs 6.56µs 149634. 0B 15.0
#> 16 cli_txt_plain 7.75µs 8.3µs 117904. 0B 23.6
#> 17 fansi_txt_plain 77.79µs 82.35µs 11814. 1.98KB 21.1
#> 18 base_txt_plain 4.13µs 4.2µs 232850. 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.81µs 111.16µs 8748. 11.88KB 16.7
#> 2 base_ansi 1.37µs 1.41µs 686492. 0B 0
#> 3 cli_plain 85.88µs 89.91µs 10780. 8.73KB 14.5
#> 4 base_plain 1.03µs 1.08µs 881693. 0B 0
#> 5 cli_vec_ansi 4.13ms 4.22ms 232. 838.77KB 29.0
#> 6 base_vec_ansi 77.33µs 77.64µs 12417. 848B 0
#> 7 cli_vec_plain 2.32ms 2.38ms 418. 816.9KB 29.9
#> 8 base_vec_plain 45.62µs 46.57µs 21245. 848B 0
#> 9 cli_txt_ansi 14.34ms 14.41ms 69.2 114.42KB 6.70
#> 10 base_txt_ansi 81.05µs 81.5µs 12130. 0B 0
#> 11 cli_txt_plain 268.27µs 278.35µs 3517. 18.16KB 4.05
#> 12 base_txt_plain 43.47µs 43.93µs 22450. 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 111.5µs 118.9µs 8141. 0B 21.1
#> 2 base_ansi 16.7µs 17.9µs 54004. 0B 21.6
#> 3 cli_plain 110.3µs 116.6µs 8335. 0B 21.0
#> 4 base_plain 16.7µs 17.8µs 54527. 0B 21.8
#> 5 cli_vec_ansi 208.8µs 218.2µs 4500. 7.2KB 12.5
#> 6 base_vec_ansi 56.7µs 62.6µs 15650. 1.66KB 4.68
#> 7 cli_vec_plain 192µs 202.5µs 4855. 7.2KB 12.4
#> 8 base_vec_plain 50.5µs 56.1µs 17448. 1.66KB 6.11
#> 9 cli_txt_ansi 182.8µs 190.3µs 5145. 0B 14.5
#> 10 base_txt_ansi 41.1µs 42.4µs 23089. 0B 9.24
#> 11 cli_txt_plain 167.2µs 174.7µs 5600. 0B 14.5
#> 12 base_txt_plain 35.3µs 36.7µs 26615. 0B 7.99
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.21µs 8.78µs 110318. 0B 22.1
#> 2 base 892.09ns 962.06ns 980173. 0B 0
#> 3 cli_vec 23.24µs 23.98µs 40873. 448B 12.3
#> 4 base_vec 11.74µs 11.88µs 82976. 448B 0
#> 5 cli_txt 23.43µs 24.07µs 40779. 0B 8.16
#> 6 base_txt 12.66µs 12.74µs 77298. 0B 0
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.28µs 8.84µs 110028. 0B 22.0
#> 2 base 1.32µs 1.39µs 688330. 0B 0
#> 3 cli_vec 28.78µs 29.69µs 33087. 448B 6.62
#> 4 base_vec 50.66µs 51.26µs 19295. 448B 2.01
#> 5 cli_txt 29.3µs 30.05µs 32692. 0B 6.54
#> 6 base_txt 86.98µs 87.8µs 11284. 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.69µs 9.3µs 103958. 0B 31.2
#> 2 base 911.07ns 982.1ns 966932. 0B 0
#> 3 cli_vec 19.9µs 20.6µs 47552. 448B 14.3
#> 4 base_vec 11.75µs 11.9µs 83050. 448B 0
#> 5 cli_txt 20.54µs 21.2µs 45146. 0B 9.03
#> 6 base_txt 12.65µs 12.7µs 71656. 0B 7.17
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.52µs 7.01µs 137633. 22.1KB 27.5
#> 2 base 1.08µs 1.15µs 813548. 0B 81.4
#> 3 cli_vec 28.85µs 29.7µs 33097. 1.7KB 6.62
#> 4 base_vec 8.27µs 8.55µs 115237. 848B 0
#> 5 cli_txt 6.57µs 7.06µs 136798. 0B 27.4
#> 6 base_txt 5.74µs 5.81µs 168407. 0B 16.8
Session info
sessioninfo::session_info()
#> ─ Session info ──────────────────────────────────────────────────────
#> setting value
#> version R version 4.5.1 (2025-06-13)
#> 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-08-15
#> 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-08-15 [1] local
#> codetools 0.2-20 2024-03-31 [3] CRAN (R 4.5.1)
#> desc 1.4.3 2023-12-10 [1] RSPM
#> digest 0.6.37 2024-08-19 [1] RSPM
#> evaluate 1.0.4 2025-06-18 [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.11.0 2025-07-04 [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.3.0 2025-06-08 [1] RSPM
#> utf8 1.2.6 2025-06-08 [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.1/lib/R/site-library
#> [3] /opt/R/4.5.1/lib/R/library
#> * ── Packages attached to the search path.
#>
#> ─────────────────────────────────────────────────────────────────────