Benchmark

This small benchmark compares the performance of the base64 encoding/decoding in package base64url with the implementations in the packages base64enc and openssl.

Encoding of a single string

library(base64url)
library(base64enc)
library(openssl)
## Linking to: OpenSSL 3.5.5 27 Jan 2026
library(microbenchmark)

x = "plain text"
microbenchmark(
  base64url = base64_urlencode(x),
  base64enc = base64encode(charToRaw(x)),
  openssl = base64_encode(x)
)
## Unit: nanoseconds
##       expr   min      lq     mean  median      uq    max neval
##  base64url   581   631.0   952.31   746.5   851.0  20098   100
##  base64enc  1592  1733.0  4054.89  1903.0  2109.5 209541   100
##    openssl 13716 14196.5 16614.09 14537.5 14973.0 155050   100

Decoding of a single string

x = "N0JBLlRaUTp1bi5KOW4xWStNWEJoLHRQaDZ3"
microbenchmark(
  base64url = base64_urldecode(x),
  base64enc = rawToChar(base64decode(x)),
  openssl = rawToChar(base64_decode(x))
)
## Unit: nanoseconds
##       expr   min      lq     mean  median      uq    max neval
##  base64url   561   631.0  1217.12   791.5   962.0  39855   100
##  base64enc  2114  2429.5  3521.34  2745.5  3110.5  76754   100
##    openssl 20799 21820.5 24351.79 22392.0 22807.5 132668   100

Encoding and decoding of character vectors

Here, the task has changed from encoding/decoding a single string to processing multiple strings stored inside a character vector. First, we create a small utility function which returns n random strings with a random number of characters (between 1 and 32) each.

rand = function(n, min = 1, max = 32) {
  chars = c(letters, LETTERS, as.character(0:9), c(".", ":", ",", "+", "-", "*", "/"))
  replicate(n, paste0(sample(chars, sample(min:max, 1), replace = TRUE), collapse = ""))
}
set.seed(1)
rand(10)
##  [1] "*MaHQn6Yu1gKKHRGIPLtBtRNR"       "MYPfxFnbSrv,mNVwCmvBVGSuE"      
##  [3] "qV:7YH"                          "aQ6zo5CxPV"                     
##  [5] "Mx0NIQaCvBK8T-YRW73WX"           "gtxY0pbV,R+sqHEITspNiXx"        
##  [7] "FMKlnpob,-"                      "qeOEJWOC:a040XDbJNK3AOo4"       
##  [9] "9fdI4y"                          "KB9tCP7,BElRzGd0xKon03XtbcLoB2/"

Only base64url is vectorized for string input, the alternative implementations need wrappers to process character vectors:

base64enc_encode = function(x) {
  vapply(x, function(x) base64encode(charToRaw(x)), NA_character_, USE.NAMES = FALSE)
}

openssl_encode = function(x) {
  vapply(x, function(x) base64_encode(x), NA_character_, USE.NAMES = FALSE)
}

base64enc_decode = function(x) {
  vapply(x, function(x) rawToChar(base64decode(x)), NA_character_, USE.NAMES = FALSE)
}

openssl_decode = function(x) {
  vapply(x, function(x) rawToChar(base64_decode(x)), NA_character_, USE.NAMES = FALSE)
}

The following benchmark measures the runtime to encode 1000 random strings and then decode them again:

set.seed(1)
x = rand(1000)
microbenchmark(
  base64url = base64_urldecode(base64_urlencode(x)),
  base64enc = base64enc_decode(base64enc_encode(x)),
  openssl = openssl_decode(openssl_encode(x))
)
## Unit: microseconds
##       expr       min         lq       mean    median         uq       max neval
##  base64url   188.252   205.7795   243.3992   230.325   262.7855   532.634   100
##  base64enc  5204.619  5295.7140  5752.3304  5353.316  5457.6005 10161.384   100
##    openssl 37675.340 39688.3590 40391.4887 39976.212 40222.3960 84799.213   100