$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: 0x56200ee4a100> <environment: 0x56200f9078b0>

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        27.38µs   34.7µs    25782.    99.2KB     23.2
#> 2 plain       26.69µs   35.1µs    25623.        0B     25.6
#> 3 base         7.93µs   10.2µs    88798.    48.4KB     17.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        28.51µs   36.6µs    24986.        0B     27.5
#> 2 plain       28.34µs   37.3µs    23625.        0B     26.0
#> 3 base         8.89µs   11.4µs    82122.        0B     32.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        65.82µs  81.53µs    11203.   75.02KB     21.5
#> 2 plain       50.62µs  67.14µs    12745.    8.73KB     17.1
#> 3 base         1.49µs   2.73µs   371582.        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          208µs    281µs     3044.   33.16KB     21.7
#> 2 plain         205µs    265µs     3231.    1.09KB     21.7

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          3.94µs   5.49µs   167764.    9.19KB     33.6
#>  2 fansi_ansi        18.9µs  25.03µs    37988.    4.18KB     30.4
#>  3 cli_plain         3.95µs   4.95µs   172400.        0B     34.5
#>  4 fansi_plain      19.46µs  21.71µs    40783.      688B     32.7
#>  5 cli_vec_ansi      5.25µs   6.12µs   141072.      448B     28.2
#>  6 fansi_vec_ansi    27.7µs  30.43µs    30073.    5.02KB     24.1
#>  7 cli_vec_plain     5.64µs   6.44µs   143102.      448B     14.3
#>  8 fansi_vec_plain  27.65µs  31.13µs    29082.    5.02KB     23.3
#>  9 cli_txt_ansi      3.97µs   4.72µs   195180.        0B     39.0
#> 10 fansi_txt_ansi   19.15µs  22.04µs    41775.      688B     33.4
#> 11 cli_txt_plain     4.79µs   5.59µs   167009.        0B     33.4
#> 12 fansi_txt_plain  27.46µs  31.34µs    29798.    5.02KB     23.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          55.2µs   60.9µs    15407.    22.6KB     8.22
#> 2 fansi        92.4µs  101.8µs     9506.    55.3KB    10.4

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          4.66µs   5.48µs   168888.        0B    33.8 
#>  2 fansi_ansi       48.72µs  57.58µs    16245.   38.83KB    26.0 
#>  3 base_ansi       628.88ns 673.93ns  1228558.        0B     0   
#>  4 cli_plain         4.69µs   5.41µs   170937.        0B    34.2 
#>  5 fansi_plain      49.83µs  58.44µs    15801.      688B    26.0 
#>  6 base_plain         595ns 637.02ns  1308860.        0B     0   
#>  7 cli_vec_ansi     21.14µs  26.17µs    33487.      448B     6.70
#>  8 fansi_vec_ansi   67.31µs  77.42µs    11801.    5.02KB    19.3 
#>  9 base_vec_ansi    10.71µs  11.37µs    84354.      448B     0   
#> 10 cli_vec_plain    19.57µs  24.09µs    38994.      448B     7.80
#> 11 fansi_vec_plain  58.67µs  69.43µs    13342.    5.02KB    21.7 
#> 12 base_vec_plain    6.39µs   6.78µs   136224.      448B     0   
#> 13 cli_txt_ansi     21.07µs  25.65µs    36497.        0B     7.30
#> 14 fansi_txt_ansi    59.8µs  72.98µs    11589.      688B    17.0 
#> 15 base_txt_ansi    10.85µs   11.6µs    83493.        0B     8.35
#> 16 cli_txt_plain    18.74µs  23.33µs    39837.        0B     7.97
#> 17 fansi_txt_plain  51.18µs  59.47µs    15161.      688B    23.5 
#> 18 base_txt_plain    6.08µs   6.39µs   141674.        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          5.61µs   6.41µs   143839.        0B    28.8 
#>  2 fansi_ansi       49.36µs  55.94µs    16240.      688B    26.0 
#>  3 base_ansi       891.97ns 966.01ns   910381.        0B     0   
#>  4 cli_plain         5.49µs   6.48µs   144672.        0B    28.9 
#>  5 fansi_plain      49.39µs  61.29µs    13873.      688B    23.6 
#>  6 base_plain      732.95ns    778ns  1106163.        0B     0   
#>  7 cli_vec_ansi     23.77µs  27.98µs    34313.      448B     6.86
#>  8 fansi_vec_ansi    72.7µs  84.46µs    10701.    5.02KB    17.1 
#>  9 base_vec_ansi    33.32µs  36.73µs    26431.      448B     2.64
#> 10 cli_vec_plain    23.83µs  26.94µs    34203.      448B     6.84
#> 11 fansi_vec_plain  65.63µs  78.15µs    11384.    5.02KB    19.2 
#> 12 base_vec_plain   17.75µs  18.91µs    48462.      448B     0   
#> 13 cli_txt_ansi     24.12µs  27.62µs    34452.        0B     6.89
#> 14 fansi_txt_ansi   65.21µs  75.29µs    11932.      688B    19.2 
#> 15 base_txt_ansi    35.22µs  38.75µs    24807.        0B     0   
#> 16 cli_txt_plain    22.49µs  25.67µs    35794.        0B    10.7 
#> 17 fansi_txt_plain  57.65µs  67.64µs    13445.      688B    21.3 
#> 18 base_txt_plain   19.04µs  20.48µs    45239.        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        4.59µs    5.5µs   153942.        0B    30.8 
#> 2 cli_plain       4.28µs      5µs   182879.        0B    36.6 
#> 3 cli_vec_ansi   30.33µs  32.93µs    28271.      848B     2.83
#> 4 cli_vec_plain    7.5µs   8.83µs    99253.      848B    19.9 
#> 5 cli_txt_ansi   30.39µs  33.21µs    28492.        0B     2.85
#> 6 cli_txt_plain   5.09µs   5.95µs   144001.        0B    28.8

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          7.85µs   9.19µs    99079.        0B     39.6
#>  2 fansi_ansi       17.94µs  20.73µs    42911.    7.24KB     30.1
#>  3 cli_plain         7.61µs   9.01µs   103622.        0B     41.5
#>  4 fansi_plain      17.83µs  20.89µs    43238.      688B     30.3
#>  5 cli_vec_ansi     15.61µs  17.88µs    51715.      848B     15.5
#>  6 fansi_vec_ansi   39.75µs  44.36µs    20376.    5.41KB     17.2
#>  7 cli_vec_plain    10.11µs  11.78µs    77441.      848B     23.2
#>  8 fansi_vec_plain  26.08µs  28.95µs    31595.    4.59KB     25.3
#>  9 cli_txt_ansi      15.7µs  16.99µs    55496.        0B     16.7
#> 10 fansi_txt_ansi   31.86µs  35.43µs    25297.    5.12KB     17.7
#> 11 cli_txt_plain     8.47µs   9.63µs    93263.        0B     37.3
#> 12 fansi_txt_plain  19.06µs  22.69µs    39158.      688B     27.4

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          78.4µs  93.17µs     9957.  104.31KB    28.2 
#>  2 fansi_ansi       75.63µs 147.19µs     7365.  106.34KB    21.7 
#>  3 base_ansi         3.13µs      4µs   196330.      224B     0   
#>  4 cli_plain        78.36µs  95.85µs     8764.    8.09KB    23.8 
#>  5 fansi_plain      75.42µs  90.71µs    10177.    9.62KB    28.6 
#>  6 base_plain        2.75µs   3.12µs   286042.        0B     0   
#>  7 cli_vec_ansi      4.84ms   5.42ms      169.  823.77KB    34.3 
#>  8 fansi_vec_ansi  779.17µs 874.73µs     1097.  846.81KB    22.4 
#>  9 base_vec_ansi   113.21µs 130.77µs     7275.    22.7KB     4.15
#> 10 cli_vec_plain     4.93ms   5.32ms      179.  823.77KB    34.8 
#> 11 fansi_vec_plain 745.12µs 842.39µs     1144.  845.98KB    25.1 
#> 12 base_vec_plain   81.94µs  93.07µs     9568.      848B     2.02
#> 13 cli_txt_ansi      2.68ms   2.91ms      325.    63.6KB     2.02
#> 14 fansi_txt_ansi    1.16ms   2.06ms      427.   35.05KB     0   
#> 15 base_txt_ansi    95.47µs 195.33µs     4963.   18.47KB     2.03
#> 16 cli_txt_plain     1.81ms      3ms      355.    63.6KB     0   
#> 17 fansi_txt_plain 356.61µs 431.11µs     1756.    30.6KB     4.09
#> 18 base_txt_plain   64.98µs   82.4µs    10533.   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        100.64µs 119.24µs     8194.   33.81KB    19.5 
#>  2 fansi_ansi       54.46µs  69.64µs    13971.   31.43KB    17.6 
#>  3 base_ansi         1.03µs   1.54µs   617372.     4.2KB     0   
#>  4 cli_plain        58.52µs 106.61µs    10370.        0B    23.8 
#>  5 fansi_plain      34.29µs   43.3µs    18516.      872B    23.7 
#>  6 base_plain         912ns   1.42µs   665948.        0B    66.6 
#>  7 cli_vec_ansi    169.86µs 290.45µs     3757.   16.73KB     8.34
#>  8 fansi_vec_ansi   84.67µs  94.92µs     9678.    5.59KB    14.8 
#>  9 base_vec_ansi    24.96µs  28.15µs    33362.      848B     0   
#> 10 cli_vec_plain   129.78µs 143.59µs     6303.   16.73KB    15.0 
#> 11 fansi_vec_plain  82.03µs  91.89µs     9952.    5.59KB    14.8 
#> 12 base_vec_plain   20.43µs   22.3µs    42159.      848B     0   
#> 13 cli_txt_ansi     66.74µs  77.28µs    11666.        0B    25.8 
#> 14 fansi_txt_ansi   33.36µs  38.95µs    23606.      872B    30.7 
#> 15 base_txt_ansi   790.93ns 843.95ns   990315.        0B     0   
#> 16 cli_txt_plain    60.26µs  68.77µs    13703.        0B    32.8 
#> 17 fansi_txt_plain  33.83µs  38.83µs    23770.      872B    30.9 
#> 18 base_txt_plain  735.98ns 779.98ns  1163322.        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        187.28µs 219.18µs    4028.         0B     28.1
#>  2 fansi_ansi       60.17µs     70µs   12310.    97.33KB     26.2
#>  3 base_ansi        21.58µs  24.58µs   37784.         0B     30.3
#>  4 cli_plain       110.98µs 129.96µs    6919.         0B     28.2
#>  5 fansi_plain      59.85µs  69.89µs   12850.       872B     28.2
#>  6 base_plain       17.45µs  20.54µs   41799.         0B     25.1
#>  7 cli_vec_ansi     21.43ms  22.17ms      41.9    2.48KB     90.9
#>  8 fansi_vec_ansi  173.15µs 194.06µs    4684.     7.25KB     12.6
#>  9 base_vec_ansi     1.61ms   1.76ms     543.    48.18KB     30.5
#> 10 cli_vec_plain    12.59ms  13.16ms      66.9    2.48KB     38.7
#> 11 fansi_vec_plain 142.77µs 158.82µs    5715.     6.42KB     16.9
#> 12 base_vec_plain    1.15ms   1.29ms     701.     47.4KB     27.9
#> 13 cli_txt_ansi     18.13ms  18.58ms      51.4  507.59KB     12.8
#> 14 fansi_txt_ansi  159.87µs 174.87µs    5267.     6.77KB     12.5
#> 15 base_txt_ansi     1.39ms    1.6ms     597.   582.06KB     15.8
#> 16 cli_txt_plain     1.15ms   1.33ms     717.   369.84KB     13.1
#> 17 fansi_txt_plain 125.37µs 138.43µs    6823.     2.51KB     17.0
#> 18 base_txt_plain  898.29µs   1.05ms     923.   367.31KB     15.5

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          4.56µs   5.31µs   175165.   24.81KB    35.0 
#>  2 fansi_ansi       47.98µs   55.3µs    16643.   28.48KB    28.4 
#>  3 base_ansi       674.04ns 762.99ns  1076565.        0B   108.  
#>  4 cli_plain         4.42µs   5.25µs   175628.        0B    35.1 
#>  5 fansi_plain      48.08µs  55.29µs    16895.    1.98KB    28.6 
#>  6 base_plain       670.9ns 708.97ns  1148273.        0B   115.  
#>  7 cli_vec_ansi     21.98µs  25.23µs    36322.     1.7KB     7.27
#>  8 fansi_vec_ansi   76.17µs   84.7µs    10964.    8.86KB    19.5 
#>  9 base_vec_ansi     4.99µs   5.41µs   171464.      848B     0   
#> 10 cli_vec_plain    17.77µs  20.88µs    42356.     1.7KB     8.47
#> 11 fansi_vec_plain  70.65µs     80µs    11739.    8.86KB    21.8 
#> 12 base_vec_plain    4.56µs   5.04µs   188671.      848B     0   
#> 13 cli_txt_ansi      4.56µs   6.15µs   143374.        0B    43.0 
#> 14 fansi_txt_ansi   48.86µs  55.66µs    16607.    1.98KB    28.6 
#> 15 base_txt_ansi     3.21µs   3.55µs   270925.        0B     0   
#> 16 cli_txt_plain     5.23µs   6.15µs   149949.        0B    30.0 
#> 17 fansi_txt_plain  48.33µs  54.86µs    16916.    1.98KB    29.4 
#> 18 base_txt_plain     2.2µs   2.31µs   407138.        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        59.11µs  71.16µs   12149.    11.85KB    21.4 
#>  2 base_ansi        1.04µs   1.11µs  841536.         0B     0   
#>  3 cli_plain       48.06µs   55.2µs   17128.     8.73KB    23.7 
#>  4 base_plain     762.05ns 828.06ns 1076875.         0B     0   
#>  5 cli_vec_ansi     3.03ms   3.47ms     246.   838.77KB    29.2 
#>  6 base_vec_ansi   57.46µs  61.56µs   14581.       848B     0   
#>  7 cli_vec_plain    1.72ms   1.96ms     470.    816.9KB    30.6 
#>  8 base_vec_plain  34.64µs  37.31µs   25292.       848B     2.53
#>  9 cli_txt_ansi    10.47ms   10.8ms      90.5  114.42KB     6.47
#> 10 base_txt_ansi   60.35µs  65.42µs   13939.         0B     0   
#> 11 cli_txt_plain  183.89µs 202.89µs    4666.    18.16KB     8.27
#> 12 base_txt_plain  31.86µs  34.53µs   26633.         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         43.4µs     50µs    18136.        0B    30.7 
#>  2 base_ansi        10.9µs   12.8µs    71294.        0B    28.5 
#>  3 cli_plain        43.3µs   50.8µs    17268.        0B    28.2 
#>  4 base_plain       10.8µs   12.6µs    75201.        0B    22.6 
#>  5 cli_vec_ansi    112.1µs    124µs     7585.     7.2KB    12.6 
#>  6 base_vec_ansi    40.9µs   46.2µs    19328.    1.66KB     6.13
#>  7 cli_vec_plain   100.9µs  111.8µs     8398.     7.2KB    14.9 
#>  8 base_vec_plain   37.1µs   42.5µs    20919.    1.66KB     6.28
#>  9 cli_txt_ansi       94µs    106µs     8897.        0B    14.6 
#> 10 base_txt_ansi      26µs   29.8µs    29415.        0B    11.8 
#> 11 cli_txt_plain    79.5µs   90.4µs     9874.        0B    15.4 
#> 12 base_txt_plain   22.9µs   32.5µs    27802.        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          5.54µs   7.55µs   119453.        0B    35.8 
#> 2 base       625.03ns   1.18µs   880356.        0B     0   
#> 3 cli_vec     21.77µs  27.88µs    33209.      448B     6.64
#> 4 base_vec    10.02µs  10.71µs    90862.      448B     0   
#> 5 cli_txt     21.68µs  24.54µs    39071.        0B    11.7 
#> 6 base_txt    11.73µs  12.64µs    76047.        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           5.4µs   6.69µs   128516.        0B    25.7 
#> 2 base        973.1ns   1.05µs   850653.        0B    85.1 
#> 3 cli_vec      21.5µs  24.24µs    39414.      448B     7.88
#> 4 base_vec     39.2µs  42.95µs    20709.      448B     0   
#> 5 cli_txt      21.6µs   25.5µs    33023.        0B     6.61
#> 6 base_txt     63.5µs  75.46µs    10317.        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          5.82µs   6.83µs   134967.        0B     27.0
#> 2 base       636.91ns 706.99ns  1152205.        0B      0  
#> 3 cli_vec     15.31µs  17.15µs    55052.      448B     16.5
#> 4 base_vec    10.06µs  10.77µs    86987.      448B      0  
#> 5 cli_txt     17.18µs  20.07µs    45605.        0B     13.7
#> 6 base_txt    11.71µs  12.58µs    75205.        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          4.47µs   9.27µs   103549.    22.1KB    20.7 
#> 2 base         1.02µs   1.51µs   620422.        0B    62.0 
#> 3 cli_vec     25.52µs   29.3µs    32575.     1.7KB     6.52
#> 4 base_vec     5.77µs   6.12µs   150199.      848B     0   
#> 5 cli_txt      4.41µs   5.19µs   176558.        0B    53.0 
#> 6 base_txt     4.67µs   5.19µs   185188.        0B     0

Session info

sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.4.1 (2024-06-14)
#>  os       Ubuntu 22.04.5 LTS
#>  system   x86_64, linux-gnu
#>  ui       X11
#>  language en
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       Etc/UTC
#>  date     2025-05-23
#>  pandoc   3.2 @ /usr/lib/rstudio-server/bin/quarto/bin/tools/x86_64/ (via rmarkdown)
#>  quarto   1.5.57 @ /usr/local/bin/quarto
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version date (UTC) lib source
#>  bench         1.1.4   2025-01-16 [2] PRISM (R 4.4.1)
#>  bslib         0.9.0   2025-01-30 [2] PRISM (R 4.4.1)
#>  cachem        1.1.0   2024-05-16 [2] PRISM (R 4.4.1)
#>  cli         * 3.6.4   2025-05-23 [1] local
#>  codetools     0.2-20  2024-03-31 [3] CRAN (R 4.4.1)
#>  desc          1.4.3   2023-12-10 [2] PRISM (R 4.4.1)
#>  digest        0.6.37  2024-08-19 [2] PRISM (R 4.4.1)
#>  evaluate      1.0.3   2025-01-10 [2] PRISM (R 4.4.1)
#>  fansi       * 1.0.6   2023-12-08 [2] PRISM (R 4.4.1)
#>  fastmap       1.2.0   2024-05-15 [2] PRISM (R 4.4.1)
#>  fs            1.6.6   2025-04-12 [2] PRISM (R 4.4.1)
#>  glue          1.8.0   2024-09-30 [2] PRISM (R 4.4.1)
#>  htmltools     0.5.8.1 2024-04-04 [2] PRISM (R 4.4.1)
#>  htmlwidgets   1.6.4   2023-12-06 [2] PRISM (R 4.4.1)
#>  jquerylib     0.1.4   2021-04-26 [2] PRISM (R 4.4.1)
#>  jsonlite      2.0.0   2025-03-27 [2] PRISM (R 4.4.1)
#>  knitr         1.50    2025-03-16 [2] PRISM (R 4.4.1)
#>  lifecycle     1.0.4   2023-11-07 [2] PRISM (R 4.4.1)
#>  magrittr      2.0.3   2022-03-30 [2] PRISM (R 4.4.1)
#>  pillar        1.10.2  2025-04-05 [2] PRISM (R 4.4.1)
#>  pkgconfig     2.0.3   2019-09-22 [2] PRISM (R 4.4.1)
#>  pkgdown       2.1.1   2024-09-17 [2] PRISM (R 4.4.1)
#>  profmem       0.6.0   2020-12-13 [2] PRISM (R 4.4.1)
#>  R6            2.6.1   2025-02-15 [2] PRISM (R 4.4.1)
#>  ragg          1.4.0   2025-04-10 [2] PRISM (R 4.4.1)
#>  rlang         1.1.6   2025-04-11 [2] PRISM (R 4.4.1)
#>  rmarkdown     2.29    2024-11-04 [2] PRISM (R 4.4.1)
#>  rstudioapi    0.17.1  2024-10-22 [2] PRISM (R 4.4.1)
#>  sass          0.4.10  2025-04-11 [2] PRISM (R 4.4.1)
#>  sessioninfo   1.2.3   2025-02-05 [2] PRISM (R 4.4.1)
#>  systemfonts   1.2.2   2025-04-04 [2] PRISM (R 4.4.1)
#>  textshaping   1.0.0   2025-01-20 [2] PRISM (R 4.4.1)
#>  tibble        3.2.1   2023-03-20 [2] PRISM (R 4.4.1)
#>  utf8          1.2.4   2023-10-22 [2] PRISM (R 4.4.1)
#>  vctrs         0.6.5   2023-12-01 [2] PRISM (R 4.4.1)
#>  xfun          0.52    2025-04-02 [2] PRISM (R 4.4.1)
#>  yaml          2.3.10  2024-07-26 [2] PRISM (R 4.4.1)
#> 
#>  [1] /tmp/RtmpMrW1qA/temp_libpath53ba43690b517
#>  [2] /cluster-data/user-homes/elizabethb/projects/prism-pkgdocs-build/rv-toml-files/rv/library/4.4/x86_64/jammy
#>  [3] /opt/R/4.4.1/lib/R/library
#>  * ── Packages attached to the search path.
#> 
#> ──────────────────────────────────────────────────────────────────────────────