Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure C++11 through C++20 compatibility #3

Merged
merged 4 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 203 additions & 24 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
@@ -1,50 +1,229 @@
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
workflow_call:
inputs:
extra-packages:
type: string
default: ""
required: false
cache-version:
type: string
default: "2"
required: false
pandoc-version:
type: string
default: "3.x"
required: false
extra-check-args:
type: string
# default: '"--run-donttest", "--no-manual", "--as-cran"'
default: "NULL"
required: false
macOS:
type: string
default: "macOS-latest"
required: false
windows:
type: string
default: "windows-latest"
required: false
ubuntu:
type: string
required: false
# To test more versions, they must be separated by a space. Ex: `"ubuntu-18.04 ubuntu-20.04`
default: "ubuntu-20.04"
minimum-r-version:
type: string
required: false
default: ""
force-windows-src:
type: boolean
required: false
default: false
rtools-35:
type: boolean
default: true
required: false
rtools-40:
type: boolean
default: true
required: false

name: R-CMD-check

jobs:
setup:
name: setup
runs-on: ubuntu-latest
outputs:
config: ${{ steps.config.outputs.config }}
steps:
# - name: devel
# id: devel
# uses: r-lib/actions/setup-r@v2
# with:
# r-version: devel
# install-r: false

- name: release
id: release
uses: r-lib/actions/setup-r@v2
with:
r-version: release
install-r: false

- name: oldrel-1
id: oldrel-1
uses: r-lib/actions/setup-r@v2
with:
r-version: oldrel-1
install-r: false

- name: oldrel-2
id: oldrel-2
uses: r-lib/actions/setup-r@v2
with:
r-version: oldrel-2
install-r: false

- name: oldrel-3
id: oldrel-3
uses: r-lib/actions/setup-r@v2
with:
r-version: oldrel-3
install-r: false

- name: oldrel-4
id: oldrel-4
uses: r-lib/actions/setup-r@v2
with:
r-version: oldrel-4
install-r: false

- name: Checkout GitHub repo
uses: rstudio/shiny-workflows/.github/internal/checkout@v1

# R is a pre-installed software
- name: Config
id: config
shell: Rscript {0}
run: |
mac <- "${{ inputs.macOS }}"
windows <- "${{ inputs.windows }}"
ubuntu <- strsplit("${{ inputs.ubuntu }}", "[[:space:],]+")[[1]]
has_src <- dir.exists("src")
min_r_ver <- "${{ inputs.minimum-r-version }}"
test_on_rtools35 <- identical("${{ inputs.rtools-35 }}", "true")
test_on_rtools40 <- identical("${{ inputs.rtools-40 }}", "true")
force_windows_src <- identical("${{ inputs.force-windows-src }}", "true")
if (force_windows_src) has_src <- TRUE

rver <- list(
# devel = "${{ steps.devel.outputs.installed-r-version }}",
# When R 4.3 was released, R version 4.4.0 was not recognized.
# However, `"devel"` is recognized within `r-lib/actions/setup-r`.
devel = "devel",
release = "${{ steps.release.outputs.installed-r-version }}",
oldrel1 = "${{ steps.oldrel-1.outputs.installed-r-version }}",
oldrel2 = "${{ steps.oldrel-2.outputs.installed-r-version }}",
oldrel3 = "${{ steps.oldrel-3.outputs.installed-r-version }}",
oldrel4 = "${{ steps.oldrel-4.outputs.installed-r-version }}"
)
job <- function(os, r, ...) {
list(os = os, r = r, ...)
}
is_valid_os <- function(os, r_ver = "") {
if (identical(os, "false")) return(FALSE)
if (identical(os, "")) return(FALSE)
if (any(nchar(c(r_ver, min_r_ver)) == 0)) return(TRUE)
if (identical(r_ver, "devel")) return(TRUE)
r_ver >= min_r_ver
}
config <- c(
list(
if (is_valid_os(mac, rver$release)) job(mac, rver$release),
if (has_src && is_valid_os(windows, "devel")) job(windows, "devel", "rtools-version" = "44"),
if (is_valid_os(windows, rver$release)) job(windows, rver$release, "rtools-version" = "43"),
if (has_src && is_valid_os(windows, "4.2")) job(windows, "4.2", "rtools-version" = "42"),
if (has_src && test_on_rtools40 && is_valid_os(windows, "4.1")) job(windows, "4.1"),
if (has_src && test_on_rtools35 && is_valid_os(windows, "3.6")) job(windows, "3.6"),
if (is_valid_os(ubuntu, rver$devel)) job(ubuntu[[1]], rver$devel, "http-user-agent" = "release")
),
if (is_valid_os(ubuntu))
unlist(recursive = FALSE, lapply(ubuntu, function(ubuntu_) {
list(
if (is_valid_os(ubuntu_, rver$release)) job(ubuntu_, rver$release),
if (is_valid_os(ubuntu_, rver$oldrel1)) job(ubuntu_, rver$oldrel1),
if (is_valid_os(ubuntu_, rver$oldrel2)) job(ubuntu_, rver$oldrel2),
if (is_valid_os(ubuntu_, rver$oldrel3)) job(ubuntu_, rver$oldrel3),
if (is_valid_os(ubuntu_, rver$oldrel4)) job(ubuntu_, rver$oldrel4)
)
}))
)
## Drop NULLs
config <- config[!vapply(config, is.null, logical(1))]
## Convert to JSON manually to save 10s installing `jsonlite`
join_and_wrap <- function(x, start, end, sep = ",") {
paste0(start, paste0(x, collapse = sep), end)
}
entries_json <- vapply(config, character(1), FUN = function(entry) {
join_and_wrap(
paste0("\"", names(entry), "\":\"", unname(entry), "\""),
"{", "}"
)
})
config_json <- join_and_wrap(entries_json, "[", "]")
cat("Config:\n", config_json, "\n", sep = "")
cat("config=", config_json, "\n", file = Sys.getenv("GITHUB_OUTPUT"), sep = "", append = TRUE)

R-CMD-check:
runs-on: ${{ matrix.config.os }}

name: ${{ matrix.config.os }} (${{ matrix.config.r }})

needs: [setup]
strategy:
fail-fast: false
matrix:
config:
- {os: macos-latest, r: 'release'}
- {os: windows-latest, r: 'release'}
- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'oldrel-1'}
config: ${{ fromJSON(needs.setup.outputs.config) }}

env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-pandoc@v2
- name: Checkout GitHub repo
uses: rstudio/shiny-workflows/.github/internal/checkout@v1

- uses: r-lib/actions/setup-r@v2
- name: Install R, system dependencies, and package dependencies
uses: rstudio/shiny-workflows/setup-r-package@v1
with:
rtools-version: ${{ matrix.config.rtools-version }}
pandoc-version: ${{ inputs.pandoc-version }}
r-version: ${{ matrix.config.r }}
http-user-agent: ${{ matrix.config.http-user-agent }}
use-public-rspm: true
cache-version: ${{ inputs.cache-version }}
needs: check
extra-packages: |
any::rcmdcheck
${{ inputs.extra-packages }}

- uses: r-lib/actions/setup-r-dependencies@v2
- name: Check package
uses: r-lib/actions/check-r-package@v2
timeout-minutes: 30
with:
extra-packages: any::rcmdcheck
needs: check
check-dir: '"check"' # matches directory below
args: 'c(${{ inputs.extra-check-args }}, "--no-manual", "--as-cran")'

- uses: r-lib/actions/check-r-package@v2
- name: "Show `testthat` output"
if: always()
run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true
shell: bash
- name: "Show install logs"
if: always()
run: find check -name '00install.out' -exec cat '{}' \; || true
shell: bash
- name: "Upload 'Check package' results"
if: failure()
uses: actions/upload-artifact@main
with:
upload-snapshots: true
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
name: ${{ matrix.config.os }}-r${{ matrix.config.r }}-results
path: "check"
16 changes: 8 additions & 8 deletions R/cpp11.R
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Generated by cpp11: do not edit by hand

compressToEncodedURIComponent_ <- function(uncompressed8) {
.Call(`_lzstringr_compressToEncodedURIComponent_`, uncompressed8)
compressToEncodedURIComponent_ <- function(bytes) {
.Call(`_lzstringr_compressToEncodedURIComponent_`, bytes)
}

decompressFromEncodedURIComponent_ <- function(compressed8) {
.Call(`_lzstringr_decompressFromEncodedURIComponent_`, compressed8)
decompressFromEncodedURIComponent_ <- function(bytes) {
.Call(`_lzstringr_decompressFromEncodedURIComponent_`, bytes)
}

compressToBase64_ <- function(uncompressed8) {
.Call(`_lzstringr_compressToBase64_`, uncompressed8)
compressToBase64_ <- function(bytes) {
.Call(`_lzstringr_compressToBase64_`, bytes)
}

decompressFromBase64_ <- function(compressed8) {
.Call(`_lzstringr_decompressFromBase64_`, compressed8)
decompressFromBase64_ <- function(bytes) {
.Call(`_lzstringr_decompressFromBase64_`, bytes)
}
76 changes: 64 additions & 12 deletions R/lzstringr-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,78 @@
## usethis namespace: end
NULL

#' @export compressToBase64
compressToBase64 <- function(string) {
safe_compress <- function(string, f) {
string <- enc2utf8(string)
compressToBase64_(string)
string <- iconv(string, from="UTF-8", to="UTF-16", toRaw=TRUE)[[1]]
result <- f(string)
chr_result <- rawToChar(as.raw(result))
chr_result
}

#' @export decompressFromBase64
decompressFromBase64 <- function(string) {
safe_decompress <- function(string, f) {
string <- enc2utf8(string)
decompressFromBase64_(string)
string <- iconv(string, from="UTF-8", to="UTF-16", toRaw=TRUE)[[1]]
result <- f(string)
chr_result <- intToUtf8(result)
chr_result
}

#' Compress a string to Base64
#'
#' This function takes a string as input and returns a compressed version of the string in Base64 format.
#'
#' @param string A character string to be compressed.
#' @return A character string representing the compressed input string in Base64 format.
#' @export
#' @examples
#' \dontrun{
#' compressToBase64("Hello, world!")
#' }
compressToBase64 <- function(string) {
safe_compress(string, compressToBase64_)
}

#' @export compressToEncodedURIComponent
#' Decompress a string from Base64
#'
#' This function takes a compressed string in Base64 format as input and returns the decompressed version of the string.
#'
#' @param string A character string in Base64 format to be decompressed.
#' @return A character string representing the decompressed input string.
#' @export
#' @examples
#' \dontrun{
#' decompressFromBase64(compressed_string)
#' }
decompressFromBase64 <- function(string) {
safe_decompress(string, decompressFromBase64_)
}

#' Compress a string to Encoded URI Component
#'
#' This function takes a string as input and returns a compressed version of the string in Encoded URI Component format.
#'
#' @param string A character string to be compressed.
#' @return A character string representing the compressed input string in Encoded URI Component format.
#' @export
#' @examples
#' \dontrun{
#' compressToEncodedURIComponent("Hello, world!")
#' }
compressToEncodedURIComponent <- function(string) {
string <- enc2utf8(string)
compressToEncodedURIComponent_(string)
safe_compress(string, compressToEncodedURIComponent_)
}

#' @export decompressFromEncodedURIComponent
#' Decompress a string from Encoded URI Component
#'
#' This function takes a compressed string in Encoded URI Component format as input and returns the decompressed version of the string.
#'
#' @param string A character string in Encoded URI Component format to be decompressed.
#' @return A character string representing the decompressed input string.
#' @export
#' @examples
#' \dontrun{
#' decompressFromEncodedURIComponent(compressed_string)
#' }
decompressFromEncodedURIComponent <- function(string) {
string <- enc2utf8(string)
decompressFromEncodedURIComponent_(string)
safe_decompress(string, decompressFromEncodedURIComponent_)
}
2 changes: 1 addition & 1 deletion README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ knitr::opts_chunk$set(
<!-- badges: end -->


The goal of lzstringr is to provide an R wrapper for the [lzstring C++ library](https://github.com/andykras/lz-string-cpp). [lzstring](https://github.com/pieroxy/lz-string) is originally a JavaScript library that provides fast and efficient string compression and decompression using a [LZ-based algorithm](https://en.wikipedia.org/wiki/Lempel–Ziv–Welch). Credit goes to [Winston Chang](https://github.com/wch) for spotting this missing R package and doing the majority of the work over at the R Shinylive repo—check out his awesome contributions which this repo is based on [here](https://github.com/posit-dev/r-shinylive/issues/70) and [here](https://github.com/posit-dev/r-shinylive/pull/71). Also, shoutout to Andy Kras for his implementation in C++ of lzstring, which you can find right [here](https://github.com/andykras/lz-string-cpp), and [pieroxy](https://github.com/pieroxy), the original brain behind lzstring in JavaScript—peek at his work over [here](https://github.com/pieroxy/lz-string).
The goal of lzstringr is to provide an R wrapper for the [lzstring C++ library](https://github.com/andykras/lz-string-cpp). [lzstring](https://github.com/pieroxy/lz-string) is originally a JavaScript library that provides fast and efficient string compression and decompression using a [LZ-based algorithm](https://en.wikipedia.org/wiki/Lempel–Ziv–Welch). Credit goes to [Winston Chang](https://github.com/wch) for spotting this missing R package and guiding me over at the R Shinylive repo—check out his awesome contributions which this repo is based on [here](https://github.com/posit-dev/r-shinylive/issues/70) and [here](https://github.com/posit-dev/r-shinylive/pull/71). Also, shoutout to Andy Kras for his implementation in C++ of lzstring, which you can find right [here](https://github.com/andykras/lz-string-cpp), and [pieroxy](https://github.com/pieroxy), the original brain behind lzstring in JavaScript—peek at his work over [here](https://github.com/pieroxy/lz-string).

## Installation

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ JavaScript library that provides fast and efficient string compression
and decompression using a [LZ-based
algorithm](https://en.wikipedia.org/wiki/Lempel–Ziv–Welch). Credit goes
to [Winston Chang](https://github.com/wch) for spotting this missing R
package and doing the majority of the work over at the R Shinylive
repo—check out his awesome contributions which this repo is based on
package and guiding me over at the R Shinylive repo—check out his
awesome contributions which this repo is based on
[here](https://github.com/posit-dev/r-shinylive/issues/70) and
[here](https://github.com/posit-dev/r-shinylive/pull/71). Also, shoutout
to Andy Kras for his implementation in C++ of lzstring, which you can
Expand Down
Loading