Skip to content

Adding Rcpp signature attribute #1184

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

Merged
merged 6 commits into from
Oct 27, 2021
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
24 changes: 17 additions & 7 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
comment:
layout: "header, diff, tree, changes"
behavior: default
require_changes: false # if true: only post the comment if coverage changes
branches: null
flags: null
paths: null
comment: false
coverage:
status:
project:
default:
target: 70% # the (on purpose low) required coverage value
threshold: 2% # the permitted delta in hitting the target
patch:
default:
target: 0% # the (on purpose low) required coverage value

# layout: "header, diff, tree, changes"
# behavior: default
# require_changes: false # if true: only post the comment if coverage changes
# branches: null
# flags: null
# paths: null
16 changes: 16 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
2021-10-15 Travers Ching <traversc@gmail.com>

* inst/tinytest/testRcppAttributePackage: Tests `signature` attribute
* inst/tinytest/test_attribute_package.R: Tests `signature` attribute

2021-10-13 Dirk Eddelbuettel <edd@debian.org>

* README.md: Switch JSS url to doi form per JSS request
* man/Rcpp-package.Rd: Idem
* man/RcppLdFlags.Rd: Idem
* inst/CITATION: Only use doi entries in three citEntry blocks

2021-10-11 Dirk Eddelbuettel <edd@debian.org>

* DESCRIPTION (Version, Date): Roll minor version
* inst/include/Rcpp/config.h: Idem

* .codecov.yml (comment): Disable codecov comments on PRs

2021-10-10 Travers Ching <traversc@gmail.com>

* src/attributes.cpp: Add `signature` attribute and syntax checks

2021-10-02 Dirk Eddelbuettel <edd@debian.org>

* .github/workflows/docker.yaml (jobs): Add container builder action
Expand Down
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: Rcpp
Title: Seamless R and C++ Integration
Version: 1.0.7.3
Version: 1.0.7.4
Date: 2021-10-01
Author: Dirk Eddelbuettel, Romain Francois, JJ Allaire, Kevin Ushey, Qiang Kou,
Nathan Russell, Inaki Ucar, Douglas Bates and John Chambers
Expand Down
4 changes: 2 additions & 2 deletions inst/include/Rcpp/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#define RCPP_VERSION_STRING "1.0.7"

// the current source snapshot (using four components, if a fifth is used in DESCRIPTION we ignore it)
#define RCPP_DEV_VERSION RcppDevVersion(1,0,7,3)
#define RCPP_DEV_VERSION_STRING "1.0.7.3"
#define RCPP_DEV_VERSION RcppDevVersion(1,0,7,4)
#define RCPP_DEV_VERSION_STRING "1.0.7.4"

#endif
11 changes: 11 additions & 0 deletions inst/tinytest/testRcppAttributePackage/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Package: testRcppAttributePackage
Type: Package
Title: Tests the signature attribute and other attributes in package compilation
Version: 1.0
Date: 2021-10-09
Author: Travers Ching
Maintainer: Dirk Eddelbuettel <edd@debian.org>
Description: Small test package part of Rcpp unit tests
License: GPL (>= 2)
Imports: Rcpp (>= 1.0.7)
LinkingTo: Rcpp
3 changes: 3 additions & 0 deletions inst/tinytest/testRcppAttributePackage/NAMESPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
useDynLib(testRcppAttributePackage, .registration=TRUE)
importFrom(Rcpp, evalCpp)
exportPattern("^[[:alpha:]]+")
95 changes: 95 additions & 0 deletions inst/tinytest/testRcppAttributePackage/src/rcpp_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::interfaces(r, cpp)]]

// [[Rcpp::export]]
List test_no_attributes(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}

// [[Rcpp::export( signature = {x = list("{A}", "B"), verbose = getOption("verbose")} )]]
List test_signature(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}

// [[Rcpp::export( rng = false, signature = {x = list("{A}", "B"), verbose = getOption("verbose")}, invisible = true )]]
List test_rng_false_signature_invisible_true(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}

// [[Rcpp::export( rng = false )]]
List test_rng_false(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}

// [[Rcpp::export( rng = true )]]
List test_rng_true(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}

// [[Rcpp::export( signature = {x = list("{A}", "B"), verbose = getOption("verbose")}, rng = true )]]
List test_rng_true_signature(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}


// [[Rcpp::export( invisible = true, rng = true )]]
List test_invisible_true_rng_true(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}

// [[Rcpp::export( invisible = true )]]
List test_invisible_true(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}

// [[Rcpp::export( invisible = true, signature = {x = list("{A}", "B"), verbose = getOption("verbose")} )]]
List test_invisible_true_signature(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}
180 changes: 180 additions & 0 deletions inst/tinytest/test_attribute_package.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
## Copyright (C) 2010 - 2020 Dirk Eddelbuettel and Romain Francois
## Copyright (C) 2021 Dirk Eddelbuettel, Romain Francois and Travers Ching
##
## This file is part of Rcpp.
##
## Rcpp is free software: you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 2 of the License, or
## (at your option) any later version.
##
## Rcpp is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Rcpp. If not, see <http://www.gnu.org/licenses/>.

.runThisTest <- Sys.getenv("RunAllRcppTests") == "yes" && Sys.getenv("RunVerboseRcppTests") == "yes"

if (! .runThisTest) exit_file("Set 'RunVerboseRcppTests' and 'RunAllRcppTests' to 'yes' to run.")

td <- tempfile()
cwd <- getwd()
dir.create(td)
pkg <- "testRcppAttributePackage"
file.copy(pkg, td, recursive = TRUE) # simpler direct path thanks to tinytest
setwd(td)
on.exit( { setwd(cwd); unlink(td, recursive = TRUE) } )
R <- shQuote(file.path( R.home(component = "bin"), "R"))
Rcpp::compileAttributes(pkg)
cmd <- paste(R, "CMD build", pkg)
invisible(system(cmd, intern=TRUE))
dir.create("templib")
pkgfile <- paste0(pkg, "_1.0.tar.gz")
install.packages(pkgfile, "templib", repos = NULL, type = "source")
require(pkg, lib.loc = "templib", character.only = TRUE)

# Test Package
options(verbose=TRUE)
expect_equal(test_no_attributes(list("{A}"), FALSE),list("{A}", FALSE))
expect_equal(test_signature(),list("{A}", TRUE))
expect_equal(test_rng_false_signature_invisible_true(),list("{A}", TRUE))
expect_equal(test_rng_false(list("{A}"), FALSE),list("{A}", FALSE))
expect_equal(test_rng_true(list("{A}"), FALSE),list("{A}", FALSE))
expect_equal(test_rng_true_signature(),list("{A}", TRUE))
expect_equal(test_invisible_true_rng_true(list("{A}"), FALSE),list("{A}", FALSE))
expect_equal(test_invisible_true(list("{A}"), FALSE),list("{A}", FALSE))
expect_equal(test_invisible_true_signature(),list("{A}", TRUE))
options(verbose=FALSE)

# Test inline

# test 0
# This example should just run and not crash
Rcpp::sourceCpp(code='
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export( rng = false, signature = {x=list("{A}", "B"), verbose = getOption("verbose")}, invisible = TRUE )]]
List test_inline(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}')
expect_equal(test_inline(), list("{A}", FALSE))
options(verbose=TRUE)
expect_equal(test_inline(), list("{A}", TRUE))
options(verbose=FALSE)

# test 1, from Enchufa2
# The verbose argument should be replaced with FALSE
Rcpp::sourceCpp(code='
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export( rng = false, signature = {x=list("{A}", "B"), verbose=FALSE} )]]
List test_inline(List x, bool verbose=true) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}')
expect_equal(test_inline(), list("{A}", FALSE))

# test 2, from Enchufa2
# This second example should not compile because of missing parameter verbose
expect_error({
Rcpp::sourceCpp(code='
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export( rng = false, signature = {x=list("{A}", "B")} )]]
List test_inline(List x, bool verbose=true) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}')
})

# test 3, from Enchufa2
# This third example should not compile because of missing end bracket }
# The bracket within the signature is taken as the end bracket, which results in
# invalid R code. There are some additional warnings due to the incorrect syntax
expect_warning({
expect_error({
Rcpp::sourceCpp(code='
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export( rng = false, signature = {x=list("{A}", "B"), verbose=FALSE )]]
List test_inline(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}', verbose=T)
})
})

# test 4, from Enchufa2
# This 4th example is missing the end bracket and will not compile
expect_error({
Rcpp::sourceCpp(code='
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export( rng = false, signature = {x=list("A", "B"), verbose=FALSE )]]
List test_inline(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}')
})

# This 5th example has brackets but incorrect R syntax
expect_error({
Rcpp::sourceCpp(code='
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export( rng = false, signature = {x=list("A", ###, verbose=FALSE} )]]
List test_inline(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}')
})

# This 6th example is missing a parameter in the signature
expect_error({
Rcpp::sourceCpp(code='
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export( rng = false, signature = {x=list("A", "B")} )]]
List test_inline(List x, bool verbose) {
if(x.size() > 0) {
CharacterVector first_element = x[0];
return List::create(first_element, verbose);
} else {
return List::create(verbose);
}
}')
})


remove.packages(pkg, lib="templib")
unlink("templib", recursive = TRUE)
setwd(cwd)
unlink(pkgfile)
Loading