Skip to content

Commit 215703f

Browse files
authored
Merge pull request #19 from pachadotdev/roxygen
Roxygen
2 parents 05c888b + 5eff766 commit 215703f

37 files changed

+2213
-1501
lines changed

R/register.R

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,16 @@ cpp_register <- function(path = ".", quiet = !is_interactive(), extension = c(".
7777
cli::cli_alert_success("generated file {.file {basename(r_path)}}")
7878
}
7979

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

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

88-
cpp_function_registration <- glue::glue_collapse(cpp_function_registration, sep = "\n")
87+
cpp_function_registration <- glue::glue_collapse(cpp_function_registration, sep = "\n")
8988

90-
extra_includes <- character()
89+
extra_includes <- character()
9190
if (pkg_links_to_rcpp(path)) {
9291
extra_includes <- c(extra_includes, "#include <cpp11/R.hpp>", "#include <Rcpp.h>", "using namespace Rcpp;")
9392
}
@@ -215,35 +214,75 @@ generate_init_functions <- function(funs) {
215214
}
216215

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

220219
if (use_package) {
221220
package_call <- glue::glue(', PACKAGE = "{package}"')
222221
package_names <- glue::glue_data(funs, '"_{package}_{name}"')
223222
} else {
224-
package_names <- glue::glue_data(funs, '`_{package}_{name}`')
223+
package_names <- glue::glue_data(funs, "`_{package}_{name}`")
225224
package_call <- ""
226225
}
227226

228-
funs$package <- package
229227
funs$package_call <- package_call
230228
funs$list_params <- vcapply(funs$args, glue_collapse_data, "{name}")
231229
funs$params <- vcapply(funs$list_params, function(x) if (nzchar(x)) paste0(", ", x) else x)
232230
is_void <- funs$return_type == "void"
233231
funs$calls <- ifelse(is_void,
234-
glue::glue_data(funs, 'invisible(.Call({package_names}{params}{package_call}))'),
235-
glue::glue_data(funs, '.Call({package_names}{params}{package_call})')
232+
glue::glue_data(funs, "invisible(.Call({package_names}{params}{package_call}))"),
233+
glue::glue_data(funs, ".Call({package_names}{params}{package_call})")
236234
)
237235

238-
out <- glue::glue_data(funs, '
239-
{name} <- function({list_params}) {{
240-
{calls}
241-
}}
242-
')
236+
# Parse and associate Roxygen comments
237+
funs$roxygen_comment <- mapply(function(file, line) {
238+
if (file.exists(file)) {
239+
comments <- extract_roxygen_comments(file)
240+
matched_comment <- ""
241+
for (comment in comments) {
242+
# Check if the comment directly precedes the function without gaps
243+
if (line == comment$line + 1) {
244+
matched_comment <- comment$text
245+
break
246+
}
247+
}
248+
matched_comment
249+
} else {
250+
""
251+
}
252+
}, funs$file, funs$line, SIMPLIFY = TRUE)
253+
254+
# Generate R functions with or without Roxygen comments
255+
out <- mapply(function(name, list_params, calls, roxygen_comment) {
256+
if (nzchar(roxygen_comment)) {
257+
glue::glue("{roxygen_comment}\n{name} <- function({list_params}) {{\n\t{calls}\n}}")
258+
} else {
259+
glue::glue("{name} <- function({list_params}) {{\n {calls}\n}}")
260+
}
261+
}, funs$name, funs$list_params, funs$calls, funs$roxygen_comment, SIMPLIFY = TRUE)
262+
263+
out <- glue::trim(out)
243264
out <- glue::glue_collapse(out, sep = "\n\n")
244265
unclass(out)
245266
}
246267

268+
extract_roxygen_comments <- function(file) {
269+
lines <- readLines(file)
270+
roxygen_start <- grep("^/\\* roxygen start", lines)
271+
roxygen_end <- grep("roxygen end \\*/$", lines)
272+
273+
if (length(roxygen_start) == 0 || length(roxygen_end) == 0) {
274+
return(list())
275+
}
276+
277+
roxygen_comments <- mapply(function(start, end) {
278+
roxygen_lines <- lines[(start + 1):(end - 1)]
279+
roxygen_lines <- sub("^", "#' ", roxygen_lines)
280+
list(line = end, text = paste(roxygen_lines, collapse = "\n"))
281+
}, roxygen_start, roxygen_end, SIMPLIFY = FALSE)
282+
283+
roxygen_comments
284+
}
285+
247286
wrap_call <- function(name, return_type, args) {
248287
call <- glue::glue('{name}({list_params})', list_params = glue_collapse_data(args, "cpp11::as_cpp<cpp11::decay_t<{type}>>({name})"))
249288
if (return_type == "void") {

R/source.R

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
#' uses 'CXX11' if unset.
1919
#' @param dir The directory to store the generated source files. `tempfile()` is
2020
#' used by default. The directory will be removed if `clean` is `TRUE`.
21+
#' @param local Passed to [dyn.load()]. If `TRUE` (the default) the shared
22+
#' library is loaded with local symbols; if `FALSE` symbols are made global
23+
#' (equivalent to `dyn.load(..., local = FALSE)`), which can be required when
24+
#' other shared objects need to see RTTI/vtable symbols from this library.
25+
#' @note See the unit test that demonstrates this usage at
26+
#' \code{tests/testthat/test-source-local.R} (shows how `local = FALSE` exports
27+
#' the necessary symbols so separate shared objects can link against them).
2128
#' @return For [cpp_source()] and `[cpp_function()]` the results of
2229
#' [dyn.load()] (invisibly). For `[cpp_eval()]` the results of the evaluated
2330
#' expression.
@@ -65,7 +72,7 @@
6572
#' }
6673
#'
6774
#' @export
68-
cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), dir = tempfile()) {
75+
cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), dir = tempfile(), local = TRUE) {
6976
stop_unless_installed(c("brio", "callr", "cli", "decor", "desc", "glue", "tibble", "vctrs"))
7077
if (!missing(file) && !file.exists(file)) {
7178
stop("Can't find `file` at this path:\n", file, "\n", call. = FALSE)
@@ -145,7 +152,7 @@ cpp_source <- function(file, code = NULL, env = parent.frame(), clean = TRUE, qu
145152
brio::write_lines(r_functions, r_path)
146153
source(r_path, local = env)
147154

148-
dyn.load(shared_lib, local = TRUE, now = TRUE)
155+
dyn.load(shared_lib, local = local, now = TRUE)
149156
}
150157

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

184191
#' @rdname cpp_source
185192
#' @export
186-
cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11")) {
193+
cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), local = TRUE) {
187194
cpp_source(code = paste(c('#include "cpp11.hpp"',
188195
"using namespace ::cpp11;",
189196
"namespace writable = ::cpp11::writable;",
@@ -193,15 +200,16 @@ cpp_function <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE,
193200
env = env,
194201
clean = clean,
195202
quiet = quiet,
196-
cxx_std = cxx_std
203+
cxx_std = cxx_std,
204+
local = local
197205
)
198206
}
199207

200208
utils::globalVariables("f")
201209

202210
#' @rdname cpp_source
203211
#' @export
204-
cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11")) {
212+
cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx_std = Sys.getenv("CXX_STD", "CXX11"), local = TRUE) {
205213
cpp_source(code = paste(c('#include "cpp11.hpp"',
206214
"using namespace ::cpp11;",
207215
"namespace writable = ::cpp11::writable;",
@@ -214,7 +222,8 @@ cpp_eval <- function(code, env = parent.frame(), clean = TRUE, quiet = TRUE, cxx
214222
env = env,
215223
clean = clean,
216224
quiet = quiet,
217-
cxx_std = cxx_std
225+
cxx_std = cxx_std,
226+
local = local
218227
)
219228
f()
220229
}

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,13 @@ Please note that the cpp11 project is released with a [Contributor Code of Condu
7878

7979
cpp11 would not exist without Rcpp.
8080
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.
81+
82+
## Clang format
83+
84+
To match GHA, use clang-format-12 to format C++ code. With systems that provide clang-format-14 or newer, you can use Docker:
85+
86+
```bash
87+
docker run --rm -v "$PWD":/work -w /work ubuntu:22.04 bash -lc "\
88+
apt-get update && apt-get install -y clang-format-12 && \
89+
find . -name '*.cpp' -o -name '*.hpp' -o -name '*.h' | xargs -r clang-format-12 -i"
90+
```

cpp11test/DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ Suggests:
2020
xml2
2121
LazyData: true
2222
Roxygen: list(markdown = TRUE)
23-
RoxygenNote: 7.1.1
23+
RoxygenNote: 7.3.2

cpp11test/NAMESPACE

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
export(roxcpp2_)
4+
export(roxcpp3_)
5+
export(roxcpp4_)
6+
export(roxcpp5_)
7+
export(roxcpp7_)
38
export(run_tests)
49
exportPattern("_$")
510
importFrom(Rcpp,sourceCpp)

cpp11test/R/cpp11.R

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,63 @@ rcpp_release_ <- function(n) {
156156
invisible(.Call(`_cpp11test_rcpp_release_`, n))
157157
}
158158

159+
notroxcpp1_ <- function(x) {
160+
.Call(`_cpp11test_notroxcpp1_`, x)
161+
}
162+
163+
#' @title Roxygenise C++ function II
164+
#' @param x numeric value
165+
#' @description Dummy function to test roxygen2. It adds 2.0 to a double.
166+
#' @export
167+
#' @examples roxcpp2_(1.0)
168+
roxcpp2_ <- function(x) {
169+
.Call(`_cpp11test_roxcpp2_`, x)
170+
}
171+
172+
#' @title Roxygenise C++ function III
173+
#' @param x numeric value
174+
#' @description Dummy function to test roxygen2. It adds 3.0 to a double.
175+
#' @export
176+
#' @examples roxcpp3_(1.0)
177+
roxcpp3_ <- function(x) {
178+
.Call(`_cpp11test_roxcpp3_`, x)
179+
}
180+
181+
#' @title Roxygenise C++ function IV
182+
#' @param x numeric value
183+
#' @description Dummy function to test roxygen2. It adds 4.0 to a double.
184+
#' @export
185+
#' @examples roxcpp4_(1.0)
186+
roxcpp4_ <- function(x) {
187+
.Call(`_cpp11test_roxcpp4_`, x)
188+
}
189+
190+
#' @title Roxygenise C++ function V
191+
#' @param x numeric value
192+
#' @description Dummy function to test roxygen2. It adds 5.0 to a double.
193+
#' @export
194+
#' @examples roxcpp5_(1.0)
195+
roxcpp5_ <- function(x) {
196+
.Call(`_cpp11test_roxcpp5_`, x)
197+
}
198+
199+
notroxcpp6_ <- function(x) {
200+
.Call(`_cpp11test_notroxcpp6_`, x)
201+
}
202+
203+
#' @title Roxygenise C++ function VII
204+
#' @param x numeric value
205+
#' @description Dummy function to test roxygen2. It adds 7.0 to a double.
206+
#' @export
207+
#' @examples
208+
#' my_fun <- function(x) {
209+
#' roxcpp7_(x)
210+
#' }
211+
#' @seealso \code{\link{roxcpp1_}}
212+
roxcpp7_ <- function(x) {
213+
.Call(`_cpp11test_roxcpp7_`, x)
214+
}
215+
159216
cpp11_safe_ <- function(x_sxp) {
160217
.Call(`_cpp11test_cpp11_safe_`, x_sxp)
161218
}
@@ -168,6 +225,26 @@ string_push_back_ <- function() {
168225
.Call(`_cpp11test_string_push_back_`)
169226
}
170227

228+
grow_strings_cpp11_ <- function(n, seed) {
229+
.Call(`_cpp11test_grow_strings_cpp11_`, n, seed)
230+
}
231+
232+
grow_strings_rcpp_ <- function(n, seed) {
233+
.Call(`_cpp11test_grow_strings_rcpp_`, n, seed)
234+
}
235+
236+
grow_strings_manual_ <- function(n, seed) {
237+
.Call(`_cpp11test_grow_strings_manual_`, n, seed)
238+
}
239+
240+
assign_cpp11_ <- function(n, seed) {
241+
.Call(`_cpp11test_assign_cpp11_`, n, seed)
242+
}
243+
244+
assign_rcpp_ <- function(n, seed) {
245+
.Call(`_cpp11test_assign_rcpp_`, n, seed)
246+
}
247+
171248
sum_dbl_for_ <- function(x) {
172249
.Call(`_cpp11test_sum_dbl_for_`, x)
173250
}
@@ -236,6 +313,14 @@ rcpp_push_and_truncate_ <- function(size_sxp) {
236313
.Call(`_cpp11test_rcpp_push_and_truncate_`, size_sxp)
237314
}
238315

316+
nullable_extptr_1 <- function() {
317+
.Call(`_cpp11test_nullable_extptr_1`)
318+
}
319+
320+
nullable_extptr_2 <- function() {
321+
.Call(`_cpp11test_nullable_extptr_2`)
322+
}
323+
239324
test_destruction_inner <- function() {
240325
invisible(.Call(`_cpp11test_test_destruction_inner`))
241326
}

cpp11test/bench/strings.R

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
pkgload::load_all("cpp11test")
2+
3+
bench::press(len = as.integer(10^(0:6)), {
4+
bench::mark(
5+
assign_cpp11_(n = len, 123L),
6+
assign_rcpp_(n = len, 123L),
7+
iterations = 20
8+
)
9+
})[c("expression", "len", "min", "mem_alloc", "n_itr", "n_gc")]
10+
11+
# Longer benchmark, lots of gc
12+
len <- as.integer(10^7)
13+
bench::mark(
14+
cpp11 = cpp11_push_and_truncate_(len),
15+
rcpp = rcpp_push_and_truncate_(len),
16+
min_iterations = 200
17+
)[c("expression", "min", "mem_alloc", "n_itr", "n_gc")]
18+
19+
bench::press(len = as.integer(10^(0:6)), {
20+
bench::mark(
21+
grow_strings_cpp11_(len, 123L),
22+
grow_strings_rcpp_(len, 123L),
23+
grow_strings_manual_(len, 123L),
24+
iterations = 20
25+
)
26+
})[c("expression", "len", "min", "mem_alloc", "n_itr", "n_gc")]
27+
28+
# Longer benchmark, lots of gc
29+
len <- as.integer(10^7)
30+
bench::mark(
31+
cpp11 = cpp11_grow_strings_(len),
32+
rcpp = rcpp_grow_strings_(len),
33+
manual = manual_grow_strings_(len),
34+
min_iterations = 200
35+
)[c("expression", "min", "mem_alloc", "n_itr", "n_gc")]

cpp11test/man/roxcpp2_.Rd

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cpp11test/man/roxcpp3_.Rd

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)