Skip to content

$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: 0x55c051f9b950> <environment: 0x55c0529c9150>

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.

library(cli)
library(fansi)
options(cli.unicode = TRUE)
options(cli.num_colors = 256)
ansi <- format_inline(
  "{col_green(symbol$tick)} {.code print(x)} {.emph emphasised}"
)
plain <- ansi_strip(ansi)
vec_plain <- rep(plain, 100)
vec_ansi <- rep(ansi, 100)
vec_plain6 <- rep(plain, 6)
vec_ansi6 <- rep(plain, 6)
txt_plain <- paste(vec_plain, collapse = " ")
txt_ansi <- paste(vec_ansi, collapse = " ")
uni <- paste(
  "\U0001f477\u200d\u2640\ufe0f",
  "\U0001f477\U0001f3fb",
  "\U0001f477\u200d\u2640\ufe0f",
  "\U0001f477\U0001f3fb",
  "\U0001f477\U0001f3ff\u200d\u2640\ufe0f"
)
vec_uni <- rep(uni, 100)
txt_uni <- paste(vec_uni, collapse = " ")

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.4µs   49.7µs    19608.    99.2KB     19.0
#> 2 plain        45.6µs   49.3µs    19708.        0B     17.5
#> 3 base         11.5µs   12.6µs    76884.    48.4KB     23.1
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    18653.        0B     21.2
#> 2 plain        48.1µs   51.6µs    18847.        0B     21.4
#> 3 base         13.4µs     15µs    64761.        0B     25.9

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.81µs 121.39µs     8038.   75.01KB     14.7
#> 2 plain       89.68µs  95.09µs    10226.    8.73KB     14.7
#> 3 base         1.87µs   2.02µs   476753.        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          342µs    363µs     2697.   33.15KB     19.3
#> 2 plain         339µs    363µs     2704.    1.09KB     19.4

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.86µs   6.39µs   150786.    9.19KB     30.2
#>  2 fansi_ansi       30.34µs  33.47µs    29008.    4.18KB     23.2
#>  3 cli_plain         5.85µs   6.37µs   151689.        0B     30.3
#>  4 fansi_plain      29.62µs  33.06µs    29409.      688B     23.5
#>  5 cli_vec_ansi      7.09µs   7.73µs   126203.      448B     25.2
#>  6 fansi_vec_ansi   38.69µs  41.01µs    23681.    5.02KB     19.0
#>  7 cli_vec_plain     7.71µs    8.3µs   103528.      448B     20.7
#>  8 fansi_vec_plain  37.47µs  39.36µs    24527.    5.02KB     19.6
#>  9 cli_txt_ansi      5.66µs   6.19µs   154759.        0B     31.0
#> 10 fansi_txt_ansi   29.94µs  31.81µs    30568.      688B     24.5
#> 11 cli_txt_plain     6.51µs      7µs   139393.        0B     27.9
#> 12 fansi_txt_plain  37.42µs  39.64µs    24527.    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.1µs     61µs    16102.    22.6KB     8.18
#> 2 fansi       115.5µs    119µs     8239.    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.89µs   7.49µs   129566.        0B    25.9 
#>  2 fansi_ansi       92.22µs  97.19µs     9949.   38.83KB    14.6 
#>  3 base_ansi       880.91ns 922.01ns   996638.        0B    99.7 
#>  4 cli_plain         6.76µs    7.5µs   129572.        0B    25.9 
#>  5 fansi_plain       91.2µs  96.82µs     9999.      688B    14.7 
#>  6 base_plain      791.04ns 871.02ns  1039007.        0B   104.  
#>  7 cli_vec_ansi      28.5µs   29.6µs    33004.      448B     3.30
#>  8 fansi_vec_ansi  112.89µs 117.98µs     8248.    5.02KB    14.8 
#>  9 base_vec_ansi    15.97µs  16.08µs    61080.      448B     0   
#> 10 cli_vec_plain    26.67µs  27.59µs    35453.      448B     7.09
#> 11 fansi_vec_plain 102.47µs 108.06µs     8979.    5.02KB    14.8 
#> 12 base_vec_plain    9.53µs   9.61µs   102155.      448B     0   
#> 13 cli_txt_ansi     27.94µs  28.83µs    34052.        0B     6.81
#> 14 fansi_txt_ansi   104.5µs 109.67µs     8869.      688B    14.6 
#> 15 base_txt_ansi    15.62µs  15.68µs    62807.        0B     0   
#> 16 cli_txt_plain    26.19µs  26.93µs    36403.        0B     7.28
#> 17 fansi_txt_plain  94.05µs  99.48µs     9763.      688B    14.6 
#> 18 base_txt_plain    9.13µs   9.66µs   102398.        0B    10.2
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.5µs    9.2µs   104988.        0B    21.0 
#>  2 fansi_ansi       92.56µs  97.62µs     9904.      688B    16.8 
#>  3 base_ansi          1.2µs   1.24µs   743720.        0B     0   
#>  4 cli_plain         8.46µs   9.25µs   104892.        0B    31.5 
#>  5 fansi_plain      92.71µs  97.58µs     9941.      688B    16.6 
#>  6 base_plain           1µs   1.04µs   907399.        0B     0   
#>  7 cli_vec_ansi     34.79µs  35.75µs    27416.      448B     5.48
#>  8 fansi_vec_ansi  119.81µs    125µs     7759.    5.02KB    12.5 
#>  9 base_vec_ansi    41.39µs  41.67µs    23738.      448B     0   
#> 10 cli_vec_plain    33.46µs  34.33µs    28596.      448B     8.58
#> 11 fansi_vec_plain 110.88µs 115.35µs     8432.    5.02KB    12.6 
#> 12 base_vec_plain   21.62µs  21.92µs    44982.      448B     4.50
#> 13 cli_txt_ansi     34.69µs  35.52µs    27535.        0B     5.51
#> 14 fansi_txt_ansi  111.47µs 116.78µs     8335.      688B    12.5 
#> 15 base_txt_ansi    44.12µs  44.34µs    22269.        0B     2.23
#> 16 cli_txt_plain    32.96µs  33.71µs    29125.        0B     5.83
#> 17 fansi_txt_plain 101.84µs 106.88µs     9115.      688B    14.6 
#> 18 base_txt_plain   23.18µs  23.84µs    40611.        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.79µs   7.43µs   130250.        0B    13.0 
#> 2 cli_plain       6.39µs   7.01µs   138874.        0B    27.8 
#> 3 cli_vec_ansi   33.42µs  34.57µs    28429.      848B     5.69
#> 4 cli_vec_plain   10.3µs  10.96µs    89111.      848B     8.91
#> 5 cli_txt_ansi   32.83µs  33.86µs    28898.        0B     5.78
#> 6 cli_txt_plain   7.21µs    7.8µs   125015.        0B    12.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          26.2µs   27.8µs    34915.        0B     28.0
#>  2 fansi_ansi        27.8µs   29.8µs    32255.    7.24KB     22.6
#>  3 cli_plain           26µs   27.8µs    34950.        0B     28.0
#>  4 fansi_plain       27.5µs   29.3µs    33130.      688B     26.5
#>  5 cli_vec_ansi      35.3µs     37µs    26282.      848B     21.0
#>  6 fansi_vec_ansi    53.4µs     56µs    17428.    5.41KB     12.6
#>  7 cli_vec_plain     28.9µs   30.7µs    31328.      848B     25.1
#>  8 fansi_vec_plain   36.4µs   38.4µs    25313.    4.59KB     20.3
#>  9 cli_txt_ansi      35.4µs   37.2µs    26068.        0B     20.9
#> 10 fansi_txt_ansi    44.5µs   46.7µs    20863.    5.12KB     16.9
#> 11 cli_txt_plain     26.9µs   28.7µs    33900.        0B     27.1
#> 12 fansi_txt_plain   28.6µs   30.3µs    32144.      688B     22.5

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        165.45µs 173.19µs     5601.  104.31KB    19.1 
#>  2 fansi_ansi      128.18µs 135.43µs     7205.  106.35KB    19.3 
#>  3 base_ansi         4.16µs   4.53µs   214797.      224B    21.5 
#>  4 cli_plain       164.35µs    172µs     5659.    8.09KB    19.0 
#>  5 fansi_plain     125.81µs 132.75µs     7238.    9.62KB    19.2 
#>  6 base_plain        3.62µs    3.9µs   247575.        0B     0   
#>  7 cli_vec_ansi      7.57ms   7.72ms      129.  823.77KB    28.9 
#>  8 fansi_vec_ansi    1.08ms   1.12ms      859.  846.81KB    17.5 
#>  9 base_vec_ansi   159.63µs 165.24µs     5929.    22.7KB     2.05
#> 10 cli_vec_plain     7.71ms   7.84ms      126.  823.77KB    25.8 
#> 11 fansi_vec_plain   1.04ms   1.08ms      890.  845.98KB    17.7 
#> 12 base_vec_plain  106.56µs 110.01µs     8916.      848B     4.07
#> 13 cli_txt_ansi      3.44ms   3.48ms      284.    63.6KB     0   
#> 14 fansi_txt_ansi    1.55ms   1.57ms      632.   35.05KB     2.02
#> 15 base_txt_ansi   138.29µs 149.71µs     6547.   18.47KB     2.03
#> 16 cli_txt_plain     2.37ms   2.41ms      413.    63.6KB     0   
#> 17 fansi_txt_plain 529.69µs 568.88µs     1736.    30.6KB     6.20
#> 18 base_txt_plain   87.53µs  90.81µs    10784.   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        151.05µs  159.8µs     6017.   33.81KB     23.8
#>  2 fansi_ansi       54.48µs  58.56µs    16299.   31.43KB     21.4
#>  3 base_ansi         1.05µs   1.09µs   867019.     4.2KB      0  
#>  4 cli_plain        147.3µs 154.99µs     6219.        0B     22.3
#>  5 fansi_plain      53.63µs  56.52µs    17183.      872B     23.6
#>  6 base_plain      990.93ns   1.03µs   912273.        0B      0  
#>  7 cli_vec_ansi    275.91µs 284.93µs     3455.   16.73KB     12.6
#>  8 fansi_vec_ansi  122.94µs 128.03µs     7564.    5.59KB     12.6
#>  9 base_vec_ansi    36.07µs  36.48µs    27095.      848B      0  
#> 10 cli_vec_plain   228.43µs 238.72µs     4096.   16.73KB     14.8
#> 11 fansi_vec_plain 119.34µs 124.28µs     7856.    5.59KB     12.6
#> 12 base_vec_plain   30.18µs  30.87µs    31999.      848B      0  
#> 13 cli_txt_ansi    158.15µs 165.35µs     5893.        0B     21.3
#> 14 fansi_txt_ansi   53.87µs  57.65µs    16854.      872B     21.3
#> 15 base_txt_ansi     1.09µs   1.14µs   828871.        0B     82.9
#> 16 cli_txt_plain   147.64µs 155.53µs     6273.        0B     21.3
#> 17 fansi_txt_plain  53.62µs   57.7µs    16404.      872B     23.8
#> 18 base_txt_plain    1.01µs   1.05µs   910095.        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        403.28µs 428.23µs    2296.         0B     21.5
#>  2 fansi_ansi       97.48µs 104.14µs    9290.    97.33KB     19.1
#>  3 base_ansi         38.6µs  41.04µs   23347.         0B     21.0
#>  4 cli_plain       278.49µs 292.56µs    3345.         0B     19.1
#>  5 fansi_plain      96.91µs 102.34µs    9488.       872B     22.6
#>  6 base_plain       31.69µs  33.45µs   28951.         0B     17.4
#>  7 cli_vec_ansi     42.83ms  42.83ms      23.3    2.48KB    257. 
#>  8 fansi_vec_ansi  245.26µs 254.78µs    3858.     7.25KB     10.4
#>  9 base_vec_ansi     2.25ms   2.35ms     424.    48.18KB     24.9
#> 10 cli_vec_plain    29.16ms  29.27ms      34.1    2.48KB     38.3
#> 11 fansi_vec_plain  204.5µs 213.16µs    4585.     6.42KB     12.5
#> 12 base_vec_plain    1.63ms    1.7ms     583.     47.4KB     24.8
#> 13 cli_txt_ansi     24.22ms   24.4ms      40.9  507.59KB     10.2
#> 14 fansi_txt_ansi   233.4µs 242.68µs    4050.     6.77KB     10.4
#> 15 base_txt_ansi     1.24ms   1.29ms     761.   582.06KB     18.5
#> 16 cli_txt_plain     1.27ms   1.31ms     746.   369.84KB     18.2
#> 17 fansi_txt_plain 185.36µs 192.98µs    5032.     2.51KB     10.4
#> 18 base_txt_plain  845.45µs 881.31µs    1109.   367.31KB     20.7

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.96µs   7.76µs   123007.   24.81KB    24.6 
#>  2 fansi_ansi       79.42µs  84.26µs    11421.   28.48KB    21.5 
#>  3 base_ansi         1.01µs   1.06µs   863271.        0B     0   
#>  4 cli_plain         6.71µs   7.45µs   128225.        0B    38.5 
#>  5 fansi_plain      79.06µs  84.37µs    11416.    1.98KB    20.1 
#>  6 base_plain      973.12ns   1.03µs   916158.        0B     0   
#>  7 cli_vec_ansi     27.32µs  28.39µs    34575.     1.7KB     6.92
#>  8 fansi_vec_ansi   114.3µs 119.37µs     8166.    8.86KB    14.9 
#>  9 base_vec_ansi     5.93µs   6.06µs   161606.      848B     0   
#> 10 cli_vec_plain    23.07µs   24.2µs    40102.     1.7KB    12.0 
#> 11 fansi_vec_plain 108.94µs 113.34µs     8602.    8.86KB    14.9 
#> 12 base_vec_plain    5.75µs   5.87µs   166460.      848B     0   
#> 13 cli_txt_ansi      6.79µs   7.42µs   129874.        0B    26.0 
#> 14 fansi_txt_ansi   77.31µs  82.47µs    11800.    1.98KB    21.4 
#> 15 base_txt_ansi     5.18µs   5.23µs   186185.        0B     0   
#> 16 cli_txt_plain     7.58µs   8.22µs   117945.        0B    35.4 
#> 17 fansi_txt_plain  78.34µs  82.92µs    11743.    1.98KB    19.2 
#> 18 base_txt_plain    3.36µs   3.44µs   260241.        0B    26.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       106.77µs  112.3µs    8650.    11.85KB    14.7 
#>  2 base_ansi         1.3µs   1.34µs  705129.         0B    70.5 
#>  3 cli_plain       85.86µs  89.91µs   10779.     8.73KB    14.6 
#>  4 base_plain        973ns   1.04µs  931508.         0B     0   
#>  5 cli_vec_ansi     4.16ms   4.28ms     233.   838.77KB    26.4 
#>  6 base_vec_ansi   74.23µs  74.68µs   13206.       848B     0   
#>  7 cli_vec_plain    2.32ms    2.4ms     416.    816.9KB    30.5 
#>  8 base_vec_plain  43.69µs  44.07µs   22389.       848B     0   
#>  9 cli_txt_ansi    13.64ms  13.74ms      72.6  114.42KB     6.60
#> 10 base_txt_ansi    74.8µs  76.11µs   13001.         0B     0   
#> 11 cli_txt_plain  272.93µs 283.27µs    3461.    18.16KB     4.06
#> 12 base_txt_plain   41.3µs  43.24µs   22947.         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        109.7µs  116.6µs     8200.        0B    21.3 
#>  2 base_ansi        16.6µs   17.9µs    53452.        0B    21.4 
#>  3 cli_plain       110.1µs  116.1µs     8334.        0B    21.3 
#>  4 base_plain       16.7µs   17.9µs    53928.        0B    21.6 
#>  5 cli_vec_ansi    205.2µs  214.9µs     4549.     7.2KB    12.5 
#>  6 base_vec_ansi    55.7µs   64.1µs    15350.    1.66KB     4.74
#>  7 cli_vec_plain   188.1µs  199.3µs     4921.     7.2KB    12.5 
#>  8 base_vec_plain   49.7µs     57µs    17075.    1.66KB     6.11
#>  9 cli_txt_ansi    177.1µs  183.5µs     5320.        0B    14.6 
#> 10 base_txt_ansi    38.1µs   39.4µs    24212.        0B     9.69
#> 11 cli_txt_plain   161.5µs  167.2µs     5827.        0B    14.6 
#> 12 base_txt_plain   33.7µs   35.1µs    27811.        0B    11.1

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.07µs   8.72µs   111312.        0B    22.3 
#> 2 base       881.03ns 922.13ns   986240.        0B     0   
#> 3 cli_vec     23.19µs  23.96µs    40926.      448B    12.3 
#> 4 base_vec    11.59µs  11.84µs    83280.      448B     0   
#> 5 cli_txt     23.38µs  24.07µs    40768.        0B     8.16
#> 6 base_txt    12.39µs  12.46µs    78937.        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.12µs    8.8µs   110624.        0B    22.1 
#> 2 base         1.26µs   1.35µs   700220.        0B     0   
#> 3 cli_vec     28.74µs  29.63µs    33133.      448B     6.63
#> 4 base_vec     51.1µs  51.71µs    19124.      448B     2.01
#> 5 cli_txt     29.02µs  29.84µs    32792.        0B     6.56
#> 6 base_txt    87.46µs  87.97µs    11249.        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.54µs   9.19µs   105470.        0B    31.7 
#> 2 base       842.03ns 912.11ns  1013847.        0B     0   
#> 3 cli_vec     19.44µs  20.37µs    47317.      448B    14.2 
#> 4 base_vec    11.58µs  11.82µs    83404.      448B     0   
#> 5 cli_txt     20.08µs   20.9µs    46812.        0B     9.36
#> 6 base_txt    12.38µs  12.47µs    78762.        0B     7.88

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.44µs   7.03µs   137790.    22.1KB    27.6 
#> 2 base         1.04µs    1.1µs   838137.        0B    83.8 
#> 3 cli_vec     29.17µs  30.13µs    32639.     1.7KB     6.53
#> 4 base_vec     7.86µs   8.34µs   117987.      848B     0   
#> 5 cli_txt      6.36µs   7.07µs   136877.        0B    41.1 
#> 6 base_txt     5.47µs   5.53µs   176800.        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-04-24
#>  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   2025-04-24 [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.1   2024-09-17 [1] any (@2.1.1)
#>  profmem       0.6.0   2020-12-13 [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] any (@1.2.3)
#>  systemfonts   1.2.2   2025-04-04 [1] RSPM
#>  textshaping   1.0.0   2025-01-20 [1] RSPM
#>  tibble        3.2.1   2023-03-20 [1] RSPM
#>  utf8          1.2.4   2023-10-22 [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.
#> 
#> ─────────────────────────────────────────────────────────────────────