diff --git a/cpp11test/R/cpp11.R b/cpp11test/R/cpp11.R index 72c0e794..cd2ae44c 100644 --- a/cpp11test/R/cpp11.R +++ b/cpp11test/R/cpp11.R @@ -92,6 +92,14 @@ cpp11_insert_ <- function(num_sxp) { .Call(`_cpp11test_cpp11_insert_`, num_sxp) } +ordered_map_to_list_ <- function(x) { + .Call(`_cpp11test_ordered_map_to_list_`, 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) } @@ -160,34 +168,6 @@ rcpp_release_ <- function(n) { invisible(.Call(`_cpp11test_rcpp_release_`, n)) } -notroxcpp1_ <- function(x) { - .Call(`_cpp11test_notroxcpp1_`, x) -} - -roxcpp2_ <- function(x) { - .Call(`_cpp11test_roxcpp2_`, x) -} - -roxcpp3_ <- function(x) { - .Call(`_cpp11test_roxcpp3_`, x) -} - -roxcpp4_ <- function(x) { - .Call(`_cpp11test_roxcpp4_`, x) -} - -roxcpp5_ <- function(x) { - .Call(`_cpp11test_roxcpp5_`, x) -} - -notroxcpp6_ <- function(x) { - .Call(`_cpp11test_notroxcpp6_`, x) -} - -roxcpp7_ <- function(x) { - .Call(`_cpp11test_roxcpp7_`, x) -} - cpp11_safe_ <- function(x_sxp) { .Call(`_cpp11test_cpp11_safe_`, x_sxp) } diff --git a/cpp11test/src/cpp11.cpp b/cpp11test/src/cpp11.cpp index bac3a051..7d076299 100644 --- a/cpp11test/src/cpp11.cpp +++ b/cpp11test/src/cpp11.cpp @@ -180,6 +180,20 @@ extern "C" SEXP _cpp11test_cpp11_insert_(SEXP num_sxp) { return cpp11::as_sexp(cpp11_insert_(cpp11::as_cpp>(num_sxp))); END_CPP11 } +// map.cpp +SEXP ordered_map_to_list_(cpp11::doubles x); +extern "C" SEXP _cpp11test_ordered_map_to_list_(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(ordered_map_to_list_(cpp11::as_cpp>(x))); + END_CPP11 +} +// map.cpp +SEXP unordered_map_to_list_(cpp11::doubles x); +extern "C" SEXP _cpp11test_unordered_map_to_list_(SEXP x) { + BEGIN_CPP11 + return cpp11::as_sexp(unordered_map_to_list_(cpp11::as_cpp>(x))); + END_CPP11 +} // matrix.cpp SEXP gibbs_cpp(int N, int thin); extern "C" SEXP _cpp11test_gibbs_cpp(SEXP N, SEXP thin) { @@ -620,6 +634,7 @@ static const R_CallMethodDef CallEntries[] = { {"_cpp11test_my_warning_n1", (DL_FUNC) &_cpp11test_my_warning_n1, 1}, {"_cpp11test_my_warning_n1fmt", (DL_FUNC) &_cpp11test_my_warning_n1fmt, 1}, {"_cpp11test_my_warning_n2fmt", (DL_FUNC) &_cpp11test_my_warning_n2fmt, 2}, + {"_cpp11test_ordered_map_to_list_", (DL_FUNC) &_cpp11test_ordered_map_to_list_, 1}, {"_cpp11test_notroxcpp1_", (DL_FUNC) &_cpp11test_notroxcpp1_, 1}, {"_cpp11test_notroxcpp6_", (DL_FUNC) &_cpp11test_notroxcpp6_, 1}, {"_cpp11test_protect_many_", (DL_FUNC) &_cpp11test_protect_many_, 1}, @@ -669,6 +684,7 @@ static const R_CallMethodDef CallEntries[] = { {"_cpp11test_sum_int_foreach_", (DL_FUNC) &_cpp11test_sum_int_foreach_, 1}, {"_cpp11test_test_destruction_inner", (DL_FUNC) &_cpp11test_test_destruction_inner, 0}, {"_cpp11test_test_destruction_outer", (DL_FUNC) &_cpp11test_test_destruction_outer, 0}, + {"_cpp11test_unordered_map_to_list_", (DL_FUNC) &_cpp11test_unordered_map_to_list_, 1}, {"_cpp11test_upper_bound", (DL_FUNC) &_cpp11test_upper_bound, 2}, {"run_testthat_tests", (DL_FUNC) &run_testthat_tests, 1}, {NULL, NULL, 0} diff --git a/cpp11test/src/map.cpp b/cpp11test/src/map.cpp new file mode 100644 index 00000000..e4a32db4 --- /dev/null +++ b/cpp11test/src/map.cpp @@ -0,0 +1,20 @@ +#include "cpp11/as.hpp" +#include "cpp11/doubles.hpp" + +[[cpp11::register]] SEXP ordered_map_to_list_(cpp11::doubles x) { + std::map counts; + int n = x.size(); + for (int i = 0; i < n; i++) { + counts[x[i]]++; + } + return cpp11::as_sexp(counts); +} + +[[cpp11::register]] SEXP unordered_map_to_list_(cpp11::doubles x) { + std::unordered_map counts; + int n = x.size(); + for (int i = 0; i < n; i++) { + counts[x[i]]++; + } + return cpp11::as_sexp(counts); +} diff --git a/cpp11test/src/roxygen1.cpp b/cpp11test/src/roxygen1.cpp deleted file mode 100644 index 6ce5dea8..00000000 --- a/cpp11test/src/roxygen1.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "cpp11/doubles.hpp" -using namespace cpp11; - -// Test: not documented + documented - -// Not Roxygenised C++ function I -[[cpp11::register]] double notroxcpp1_(double x) { - double y = x + 1.0; - return y; -} - -/* roxygen start -@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) -roxygen end */ -[[cpp11::register]] double roxcpp2_(double x) { - double y = x + 2.0; - return y; -} diff --git a/cpp11test/src/roxygen2.cpp b/cpp11test/src/roxygen2.cpp deleted file mode 100644 index ecd50221..00000000 --- a/cpp11test/src/roxygen2.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "cpp11/doubles.hpp" -using namespace cpp11; - -// Test: documented + documented - -/* roxygen start -@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) -roxygen end */ -[[cpp11::register]] double roxcpp3_(double x) { - double y = x + 3.0; - return y; -} - -/* roxygen start -@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) -roxygen end */ -[[cpp11::register]] double roxcpp4_(double x) { - double y = x + 4.0; - return y; -} diff --git a/cpp11test/src/roxygen3.cpp b/cpp11test/src/roxygen3.cpp deleted file mode 100644 index 7ede7a08..00000000 --- a/cpp11test/src/roxygen3.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "cpp11/doubles.hpp" -using namespace cpp11; - -// Test: documented + not documented + documented - -/* roxygen start -@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) -roxygen end */ -[[cpp11::register]] double roxcpp5_(double x) { - double y = x + 5.0; - return y; -} - -// Not Roxygenised C++ function VI -[[cpp11::register]] double notroxcpp6_(double x) { - double y = x + 6.0; - return y; -} - -/* roxygen start -@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_}} -roxygen end */ -[[cpp11::register]] double roxcpp7_(double x) { - double y = x + 7.0; - return y; -} diff --git a/cpp11test/tests/testthat/test-map-to-list.R b/cpp11test/tests/testthat/test-map-to-list.R new file mode 100644 index 00000000..dc637afa --- /dev/null +++ b/cpp11test/tests/testthat/test-map-to-list.R @@ -0,0 +1,18 @@ +test_that("ordered and unordered C++ maps are converted to R lists", { + set.seed(42L) + x <- rnorm(10L) + xprime <- c(x, x[1]) + + om <- ordered_map_to_list_(x) + expect_type(om, "list") + + om_doubles <- as.double(names(om)) + expect_equal(om_doubles, sort(om_doubles)) + + omprime <- ordered_map_to_list_(xprime) + expect_equal(unlist(unique(omprime)), 1:2) + + um <- unordered_map_to_list_(xprime) + expect_type(um, "list") + expect_equal(unlist(unique(um)), 1:2) +}) diff --git a/inst/include/cpp11/as.hpp b/inst/include/cpp11/as.hpp index 49bb41aa..63d3a20a 100644 --- a/inst/include/cpp11/as.hpp +++ b/inst/include/cpp11/as.hpp @@ -2,11 +2,14 @@ #include // for modf #include // for initializer_list +#include // for std::map #include // for std::shared_ptr, std::weak_ptr, std::unique_ptr #include #include -#include // for string, basic_string -#include // for decay, enable_if, is_same, is_convertible +#include // for string, basic_string +#include // for decay, enable_if, is_same, is_convertible +#include // for std::unordered_map +#include // for std::vector #include "cpp11/R.hpp" // for SEXP, SEXPREC, Rf_xlength, R_xlen_t #include "cpp11/protect.hpp" // for stop, protect, safe, protect::function @@ -277,7 +280,7 @@ enable_if_integral as_sexp(const Container& from) { } inline SEXP as_sexp(std::initializer_list from) { - return as_sexp>(from); + return as_sexp(std::vector(from)); } template as_sexp(const Container& from) { } inline SEXP as_sexp(std::initializer_list from) { - return as_sexp>(from); + return as_sexp(std::vector(from)); } template as_sexp(const Container& from) { } inline SEXP as_sexp(std::initializer_list from) { - return as_sexp>(from); + return as_sexp(std::vector(from)); } namespace detail { @@ -361,7 +364,7 @@ enable_if_c_string as_sexp(const Container& from) { } inline SEXP as_sexp(std::initializer_list from) { - return as_sexp>(from); + return as_sexp(std::vector(from)); } template > @@ -369,4 +372,73 @@ enable_if_convertible_to_sexp as_sexp(const T& from) { return from; } +// Pacha: Specialization for std::map +// NOTE: I did not use templates to avoid clashes with doubles/function/etc. +inline SEXP as_sexp(const std::map& map) { + R_xlen_t size = map.size(); + SEXP result = PROTECT(Rf_allocVector(VECSXP, size)); + SEXP names = PROTECT(Rf_allocVector(STRSXP, size)); + + auto it = map.begin(); + for (R_xlen_t i = 0; i < size; ++i, ++it) { + SET_VECTOR_ELT(result, i, it->second); + SET_STRING_ELT(names, i, Rf_mkCharCE(it->first.c_str(), CE_UTF8)); + } + + Rf_setAttrib(result, R_NamesSymbol, names); + UNPROTECT(2); + return result; +} + +// Specialization for std::map +inline SEXP as_sexp(const std::map& map) { + R_xlen_t size = map.size(); + SEXP result = PROTECT(Rf_allocVector(VECSXP, size)); + SEXP names = PROTECT(Rf_allocVector(REALSXP, size)); + + auto it = map.begin(); + for (R_xlen_t i = 0; i < size; ++i, ++it) { + SET_VECTOR_ELT(result, i, Rf_ScalarInteger(it->second)); + REAL(names)[i] = it->first; + } + + Rf_setAttrib(result, R_NamesSymbol, names); + UNPROTECT(2); + return result; +} + +// Pacha: Specialization for std::unordered_map +inline SEXP as_sexp(const std::unordered_map& map) { + R_xlen_t size = map.size(); + SEXP result = PROTECT(Rf_allocVector(VECSXP, size)); + SEXP names = PROTECT(Rf_allocVector(STRSXP, size)); + + auto it = map.begin(); + for (R_xlen_t i = 0; i < size; ++i, ++it) { + SET_VECTOR_ELT(result, i, it->second); + SET_STRING_ELT(names, i, Rf_mkCharCE(it->first.c_str(), CE_UTF8)); + } + + Rf_setAttrib(result, R_NamesSymbol, names); + UNPROTECT(2); + return result; +} + +// Specialization for std::unordered_map +inline SEXP as_sexp(const std::unordered_map& map) { + R_xlen_t size = map.size(); + SEXP result = PROTECT(Rf_allocVector(VECSXP, size)); + SEXP names = PROTECT(Rf_allocVector(REALSXP, size)); + + auto it = map.begin(); + for (R_xlen_t i = 0; i < size; ++i, ++it) { + SET_VECTOR_ELT(result, i, Rf_ScalarInteger(it->second)); + REAL(names)[i] = it->first; + } + + Rf_setAttrib(result, R_NamesSymbol, names); + UNPROTECT(2); + return result; +} + } // namespace cpp11 diff --git a/vignettes/cpp11.Rmd b/vignettes/cpp11.Rmd index cabafc1d..89d0701f 100644 --- a/vignettes/cpp11.Rmd +++ b/vignettes/cpp11.Rmd @@ -878,8 +878,6 @@ logicals duplicated_cpp(integers x) { } ``` -````{=html} - -```` ### Exercises