Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
fd99010
implement 25% of #297
pachadotdev Dec 17, 2024
f5d6054
clang format
pachadotdev Dec 27, 2024
713f147
bool -> int + using transform for bool -> double
pachadotdev Dec 27, 2024
bbee709
fix #406
pachadotdev Jan 1, 2025
496dd6b
borrow from @traversc's push_back_fast
pachadotdev Jan 1, 2025
008ab7c
add benchmarks
pachadotdev Jan 1, 2025
6f84867
implement #431
pachadotdev Jan 1, 2025
2d4bbb5
implement #432
pachadotdev Jan 1, 2025
9673bb2
implement #435
pachadotdev Jan 1, 2025
a03a126
draft map -> list/sexp
pachadotdev Jan 1, 2025
aaed104
ordered and unordered C++ maps are converted to R lists
pachadotdev Jan 2, 2025
70c68df
template map to list conversion
pachadotdev Jan 2, 2025
9ebcf41
fix sum rcpp error on Unix systems (cpp11test)
pachadotdev Jan 3, 2025
fb3583f
roxygen comments on cpp side (works ok with 1 roxygenised function pe…
pachadotdev Jan 3, 2025
14531db
almost there with rx/no rx in the same file
pachadotdev Jan 4, 2025
c750115
correctly handles roxygen in cpp files
pachadotdev Jan 4, 2025
fb848c6
revert some styler changes to make the changes more clear
pachadotdev Jan 4, 2025
17cac60
fix multi line roxygen examples
pachadotdev Jan 4, 2025
7a436d6
add roxygen example to documentation
pachadotdev Jan 4, 2025
a781c99
consider the case where a file does not exist
pachadotdev Jan 4, 2025
f717713
do not roxygenize chunk in vignette
pachadotdev Jan 4, 2025
fbb365f
workaround for roxygen comments in cpp chunks
pachadotdev Jan 5, 2025
c91f4ef
revert to eval = F
pachadotdev Jan 5, 2025
b1d8ecd
implement #312
pachadotdev Feb 1, 2025
7a72ec9
implement fix for #445
pachadotdev May 9, 2025
fcb7756
only one cstdlib in data_frame.hpp
pachadotdev May 9, 2025
012e4e0
use inline constexpr for doubles/integers/list/logicals/strings
pachadotdev May 9, 2025
2be6542
use noexcept in protect/sexp
pachadotdev May 9, 2025
91c3bd4
noexcept in operator SEXP (attribute proxy)
pachadotdev May 9, 2025
472f40f
+ noexcept
pachadotdev May 9, 2025
4209cf0
clang format
pachadotdev May 9, 2025
b0b3f47
rollback noexcept
pachadotdev May 9, 2025
8fdaaef
clang format
pachadotdev May 9, 2025
a80ae91
fix typos
pachadotdev May 9, 2025
ff8e314
fix r_Vector
pachadotdev May 9, 2025
f7fd0e0
fix strings
pachadotdev May 9, 2025
e0229d5
rollback strings
pachadotdev May 9, 2025
ddf5300
rollback strings
pachadotdev May 9, 2025
9851423
use a lamba to unwind protect around the loop
pachadotdev Aug 26, 2025
c016918
Use values added to a vector with push_back immediately
pachadotdev Aug 26, 2025
8ee112a
fix clang format
pachadotdev Aug 26, 2025
8093e12
llvm formatt
pachadotdev Sep 7, 2025
6783944
Global symbol visibility
pachadotdev Sep 15, 2025
5114411
clang ofrmat
pachadotdev Sep 15, 2025
acdcf61
clang format
pachadotdev Sep 15, 2025
e340f78
clang format 12
pachadotdev Sep 15, 2025
3c6e5c6
clang fmt
pachadotdev Sep 15, 2025
224b9af
check unix tests
pachadotdev Sep 15, 2025
72d2f37
Merge pull request #1 from pachadotdev/issue460
pachadotdev Sep 16, 2025
36ef9b7
Merge pull request #2 from pachadotdev/issue453
pachadotdev Sep 16, 2025
2c56e1a
Merge pull request #3 from pachadotdev/issue452
pachadotdev Sep 16, 2025
7256c37
Merge pull request #4 from pachadotdev/issue406
pachadotdev Sep 16, 2025
8e7a80d
Merge pull request #5 from pachadotdev/issue297
pachadotdev Sep 16, 2025
66d37b1
Merge pull request #6 from pachadotdev/compilationspeed
pachadotdev Sep 16, 2025
1487985
Merge pull request #7 from pachadotdev/nullable_extptr
pachadotdev Sep 16, 2025
5eff766
Merge branch 'main' into roxygen
pachadotdev Sep 16, 2025
bd30629
Merge pull request #8 from pachadotdev/roxygen
pachadotdev Sep 16, 2025
b63d96c
Merge branch 'main' into 419
pachadotdev Sep 16, 2025
a33c8b5
Merge pull request #9 from pachadotdev/419
pachadotdev Sep 16, 2025
4441386
Merge branch 'main' into vignettes
pachadotdev Sep 16, 2025
49953b9
Merge pull request #10 from pachadotdev/vignettes
pachadotdev Sep 16, 2025
b041c48
Merge branch 'main' into named_arg_utf8
pachadotdev Sep 16, 2025
67f3fb1
Merge pull request #11 from pachadotdev/named_arg_utf8
pachadotdev Sep 16, 2025
55fd0f0
Merge branch 'main' into vmaxgetset
pachadotdev Sep 16, 2025
b44690d
Merge pull request #12 from pachadotdev/vmaxgetset
pachadotdev Sep 16, 2025
6b36c1a
Merge branch 'main' into 3Fto1T
pachadotdev Sep 16, 2025
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
65 changes: 52 additions & 13 deletions R/register.R
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,16 @@ cpp_register <- function(path = ".", quiet = !is_interactive(), extension = c(".
cli::cli_alert_success("generated file {.file {basename(r_path)}}")
}


call_entries <- get_call_entries(path, funs$name, package)

cpp_function_registration <- glue::glue_data(funs, ' {{
"_cpp11_{name}", (DL_FUNC) &_{package}_{name}, {n_args}}}, ',
n_args = viapply(funs$args, nrow)
)

cpp_function_registration <- glue::glue_collapse(cpp_function_registration, sep = "\n")
cpp_function_registration <- glue::glue_collapse(cpp_function_registration, sep = "\n")

extra_includes <- character()
extra_includes <- character()
if (pkg_links_to_rcpp(path)) {
extra_includes <- c(extra_includes, "#include <cpp11/R.hpp>", "#include <Rcpp.h>", "using namespace Rcpp;")
}
Expand Down Expand Up @@ -215,35 +214,75 @@ generate_init_functions <- function(funs) {
}

generate_r_functions <- function(funs, package = "cpp11", use_package = FALSE) {
funs <- funs[c("name", "return_type", "args")]
funs <- funs[c("name", "return_type", "args", "file", "line", "decoration")]

if (use_package) {
package_call <- glue::glue(', PACKAGE = "{package}"')
package_names <- glue::glue_data(funs, '"_{package}_{name}"')
} else {
package_names <- glue::glue_data(funs, '`_{package}_{name}`')
package_names <- glue::glue_data(funs, "`_{package}_{name}`")
package_call <- ""
}

funs$package <- package
funs$package_call <- package_call
funs$list_params <- vcapply(funs$args, glue_collapse_data, "{name}")
funs$params <- vcapply(funs$list_params, function(x) if (nzchar(x)) paste0(", ", x) else x)
is_void <- funs$return_type == "void"
funs$calls <- ifelse(is_void,
glue::glue_data(funs, 'invisible(.Call({package_names}{params}{package_call}))'),
glue::glue_data(funs, '.Call({package_names}{params}{package_call})')
glue::glue_data(funs, "invisible(.Call({package_names}{params}{package_call}))"),
glue::glue_data(funs, ".Call({package_names}{params}{package_call})")
)

out <- glue::glue_data(funs, '
{name} <- function({list_params}) {{
{calls}
}}
')
# Parse and associate Roxygen comments
funs$roxygen_comment <- mapply(function(file, line) {
if (file.exists(file)) {
comments <- extract_roxygen_comments(file)
matched_comment <- ""
for (comment in comments) {
# Check if the comment directly precedes the function without gaps
if (line == comment$line + 1) {
matched_comment <- comment$text
break
}
}
matched_comment
} else {
""
}
}, funs$file, funs$line, SIMPLIFY = TRUE)

# Generate R functions with or without Roxygen comments
out <- mapply(function(name, list_params, calls, roxygen_comment) {
if (nzchar(roxygen_comment)) {
glue::glue("{roxygen_comment}\n{name} <- function({list_params}) {{\n\t{calls}\n}}")
} else {
glue::glue("{name} <- function({list_params}) {{\n {calls}\n}}")
}
}, funs$name, funs$list_params, funs$calls, funs$roxygen_comment, SIMPLIFY = TRUE)

out <- glue::trim(out)
out <- glue::glue_collapse(out, sep = "\n\n")
unclass(out)
}

extract_roxygen_comments <- function(file) {
lines <- readLines(file)
roxygen_start <- grep("^/\\* roxygen start", lines)
roxygen_end <- grep("roxygen end \\*/$", lines)

if (length(roxygen_start) == 0 || length(roxygen_end) == 0) {
return(list())
}

roxygen_comments <- mapply(function(start, end) {
roxygen_lines <- lines[(start + 1):(end - 1)]
roxygen_lines <- sub("^", "#' ", roxygen_lines)
list(line = end, text = paste(roxygen_lines, collapse = "\n"))
}, roxygen_start, roxygen_end, SIMPLIFY = FALSE)

roxygen_comments
}

wrap_call <- function(name, return_type, args) {
call <- glue::glue('{name}({list_params})', list_params = glue_collapse_data(args, "cpp11::as_cpp<cpp11::decay_t<{type}>>({name})"))
if (return_type == "void") {
Expand Down
21 changes: 15 additions & 6 deletions R/source.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
#' uses 'CXX11' if unset.
#' @param dir The directory to store the generated source files. `tempfile()` is
#' used by default. The directory will be removed if `clean` is `TRUE`.
#' @param local Passed to [dyn.load()]. If `TRUE` (the default) the shared
#' library is loaded with local symbols; if `FALSE` symbols are made global
#' (equivalent to `dyn.load(..., local = FALSE)`), which can be required when
#' other shared objects need to see RTTI/vtable symbols from this library.
#' @note See the unit test that demonstrates this usage at
#' \code{tests/testthat/test-source-local.R} (shows how `local = FALSE` exports
#' the necessary symbols so separate shared objects can link against them).
#' @return For [cpp_source()] and `[cpp_function()]` the results of
#' [dyn.load()] (invisibly). For `[cpp_eval()]` the results of the evaluated
#' expression.
Expand Down Expand Up @@ -65,7 +72,7 @@
#' }
#'
#' @export
cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), dir = tempfile()) {
cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), dir = tempfile(), local = TRUE) {
stop_unless_installed(c("brio", "callr", "cli", "decor", "desc", "glue", "tibble", "vctrs"))
if (!missing(file) && !file.exists(file)) {
stop("Can't find `file` at this path:\n", file, "\n", call. = FALSE)
Expand Down Expand Up @@ -145,7 +152,7 @@ cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, qu
brio::write_lines(r_functions, r_path)
source(r_path, local = env)

dyn.load(shared_lib, local = TRUE, now = TRUE)
dyn.load(shared_lib, local = local, now = TRUE)
}

the <- new.env(parent = emptyenv())
Expand Down Expand Up @@ -183,7 +190,7 @@ generate_makevars <- function(includes, cxx_std) {

#' @rdname cpp_source
#' @export
cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11")) {
cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), local = TRUE) {
cpp_source(code = paste(c('#include "cpp11.hpp"',
"using namespace ::cpp11;",
"namespace writable = ::cpp11::writable;",
Expand All @@ -193,15 +200,16 @@ cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE,
env = env,
clean = clean,
quiet = quiet,
cxx_std = cxx_std
cxx_std = cxx_std,
local = local
)
}

utils::globalVariables("f")

#' @rdname cpp_source
#' @export
cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11")) {
cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), local = TRUE) {
cpp_source(code = paste(c('#include "cpp11.hpp"',
"using namespace ::cpp11;",
"namespace writable = ::cpp11::writable;",
Expand All @@ -214,7 +222,8 @@ cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx
env = env,
clean = clean,
quiet = quiet,
cxx_std = cxx_std
cxx_std = cxx_std,
local = local
)
f()
}
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,13 @@ Please note that the cpp11 project is released with a [Contributor Code of Condu

cpp11 would not exist without Rcpp.
Thanks to the Rcpp authors, Dirk Eddelbuettel, Romain Francois, JJ Allaire, Kevin Ushey, Qiang Kou, Nathan Russell, Douglas Bates and John Chambers for their work writing and maintaining Rcpp.

## Clang format

To match GHA, use clang-format-12 to format C++ code. With systems that provide clang-format-14 or newer, you can use Docker:

```bash
docker run --rm -v "$PWD":/work -w /work ubuntu:22.04 bash -lc "\
apt-get update && apt-get install -y clang-format-12 && \
find . -name '*.cpp' -o -name '*.hpp' -o -name '*.h' | xargs -r clang-format-12 -i"
```
3 changes: 3 additions & 0 deletions cpp11test/.Rbuildignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
^\.here$
^bench$
^LICENSE\.md$
8 changes: 5 additions & 3 deletions cpp11test/DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ Authors@R:
Description: Provides a test suite and benchmarking code for the 'cpp11' package.
License: MIT + file LICENSE
Encoding: UTF-8
LinkingTo: Rcpp, cpp11, testthat
LinkingTo: cpp11, Rcpp, testthat
Imports: cpp11, Rcpp
Suggests:
covr,
testthat,
testthat (>= 3.0.0),
pkgload,
xml2
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1
RoxygenNote: 7.3.2
Config/testthat/edition: 3
2 changes: 2 additions & 0 deletions cpp11test/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
YEAR: 2025
COPYRIGHT HOLDER: cpp11test authors
21 changes: 21 additions & 0 deletions cpp11test/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# MIT License

Copyright (c) 2025 cpp11test authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
6 changes: 6 additions & 0 deletions cpp11test/NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Generated by roxygen2: do not edit by hand

export(roxcpp2_)
export(roxcpp3_)
export(roxcpp4_)
export(roxcpp5_)
export(roxcpp7_)
export(run_tests)
exportPattern("_$")
importFrom(Rcpp,sourceCpp)
importFrom(cpp11,cpp_source)
useDynLib(cpp11test, .registration = TRUE)
97 changes: 97 additions & 0 deletions cpp11test/R/cpp11.R
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ cpp11_insert_ <- function(num_sxp) {
.Call(`_cpp11test_cpp11_insert_`, num_sxp)
}

ordered_map_to_list_ <- function(x) {
.Call(`_cpp11test_ordered_map_to_list_`, x)
}

ordered_map_to_list_2_ <- function(x) {
.Call(`_cpp11test_ordered_map_to_list_2_`, x)
}

unordered_map_to_list_ <- function(x) {
.Call(`_cpp11test_unordered_map_to_list_`, x)
}

gibbs_cpp <- function(N, thin) {
.Call(`_cpp11test_gibbs_cpp`, N, thin)
}
Expand Down Expand Up @@ -156,6 +168,63 @@ rcpp_release_ <- function(n) {
invisible(.Call(`_cpp11test_rcpp_release_`, n))
}

notroxcpp1_ <- function(x) {
.Call(`_cpp11test_notroxcpp1_`, x)
}

#' @title Roxygenise C++ function II
#' @param x numeric value
#' @description Dummy function to test roxygen2. It adds 2.0 to a double.
#' @export
#' @examples roxcpp2_(1.0)
roxcpp2_ <- function(x) {
.Call(`_cpp11test_roxcpp2_`, x)
}

#' @title Roxygenise C++ function III
#' @param x numeric value
#' @description Dummy function to test roxygen2. It adds 3.0 to a double.
#' @export
#' @examples roxcpp3_(1.0)
roxcpp3_ <- function(x) {
.Call(`_cpp11test_roxcpp3_`, x)
}

#' @title Roxygenise C++ function IV
#' @param x numeric value
#' @description Dummy function to test roxygen2. It adds 4.0 to a double.
#' @export
#' @examples roxcpp4_(1.0)
roxcpp4_ <- function(x) {
.Call(`_cpp11test_roxcpp4_`, x)
}

#' @title Roxygenise C++ function V
#' @param x numeric value
#' @description Dummy function to test roxygen2. It adds 5.0 to a double.
#' @export
#' @examples roxcpp5_(1.0)
roxcpp5_ <- function(x) {
.Call(`_cpp11test_roxcpp5_`, x)
}

notroxcpp6_ <- function(x) {
.Call(`_cpp11test_notroxcpp6_`, x)
}

#' @title Roxygenise C++ function VII
#' @param x numeric value
#' @description Dummy function to test roxygen2. It adds 7.0 to a double.
#' @export
#' @examples
#' my_fun <- function(x) {
#' roxcpp7_(x)
#' }
#' @seealso \code{\link{roxcpp1_}}
roxcpp7_ <- function(x) {
.Call(`_cpp11test_roxcpp7_`, x)
}

cpp11_safe_ <- function(x_sxp) {
.Call(`_cpp11test_cpp11_safe_`, x_sxp)
}
Expand All @@ -168,6 +237,26 @@ string_push_back_ <- function() {
.Call(`_cpp11test_string_push_back_`)
}

grow_strings_cpp11_ <- function(n, seed) {
.Call(`_cpp11test_grow_strings_cpp11_`, n, seed)
}

grow_strings_rcpp_ <- function(n, seed) {
.Call(`_cpp11test_grow_strings_rcpp_`, n, seed)
}

grow_strings_manual_ <- function(n, seed) {
.Call(`_cpp11test_grow_strings_manual_`, n, seed)
}

assign_cpp11_ <- function(n, seed) {
.Call(`_cpp11test_assign_cpp11_`, n, seed)
}

assign_rcpp_ <- function(n, seed) {
.Call(`_cpp11test_assign_rcpp_`, n, seed)
}

sum_dbl_for_ <- function(x) {
.Call(`_cpp11test_sum_dbl_for_`, x)
}
Expand Down Expand Up @@ -236,6 +325,14 @@ rcpp_push_and_truncate_ <- function(size_sxp) {
.Call(`_cpp11test_rcpp_push_and_truncate_`, size_sxp)
}

nullable_extptr_1 <- function() {
.Call(`_cpp11test_nullable_extptr_1`)
}

nullable_extptr_2 <- function() {
.Call(`_cpp11test_nullable_extptr_2`)
}

test_destruction_inner <- function() {
invisible(.Call(`_cpp11test_test_destruction_inner`))
}
Expand Down
2 changes: 2 additions & 0 deletions cpp11test/R/cpp11test-package.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#' @keywords internal
#' @exportPattern "_$"
#' @importFrom cpp11 cpp_source
#' @importFrom Rcpp sourceCpp
NULL
"_PACKAGE"

# The following block is used by usethis to automatically manage
Expand Down
3 changes: 1 addition & 2 deletions cpp11test/R/test.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ run_tests <- function(reporter = testthat::default_reporter()) {
on.exit(setwd(old))
setwd(system.file("tests", package = "cpp11test"))

library(testthat)
test_check("cpp11test", reporter = reporter)
testthat::test_check("cpp11test", reporter = reporter)
}
Loading
Loading