Skip to content

Commit c8ce428

Browse files
authored
Merge pull request #40 from pachadotdev/map-to-list-clean
Map to list clean
2 parents 933f214 + b7ce3ec commit c8ce428

File tree

9 files changed

+140
-126
lines changed

9 files changed

+140
-126
lines changed

cpp11test/R/cpp11.R

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ cpp11_insert_ <- function(num_sxp) {
9292
.Call(`_cpp11test_cpp11_insert_`, num_sxp)
9393
}
9494

95+
ordered_map_to_list_ <- function(x) {
96+
.Call(`_cpp11test_ordered_map_to_list_`, x)
97+
}
98+
99+
unordered_map_to_list_ <- function(x) {
100+
.Call(`_cpp11test_unordered_map_to_list_`, x)
101+
}
102+
95103
gibbs_cpp <- function(N, thin) {
96104
.Call(`_cpp11test_gibbs_cpp`, N, thin)
97105
}
@@ -160,34 +168,6 @@ rcpp_release_ <- function(n) {
160168
invisible(.Call(`_cpp11test_rcpp_release_`, n))
161169
}
162170

163-
notroxcpp1_ <- function(x) {
164-
.Call(`_cpp11test_notroxcpp1_`, x)
165-
}
166-
167-
roxcpp2_ <- function(x) {
168-
.Call(`_cpp11test_roxcpp2_`, x)
169-
}
170-
171-
roxcpp3_ <- function(x) {
172-
.Call(`_cpp11test_roxcpp3_`, x)
173-
}
174-
175-
roxcpp4_ <- function(x) {
176-
.Call(`_cpp11test_roxcpp4_`, x)
177-
}
178-
179-
roxcpp5_ <- function(x) {
180-
.Call(`_cpp11test_roxcpp5_`, x)
181-
}
182-
183-
notroxcpp6_ <- function(x) {
184-
.Call(`_cpp11test_notroxcpp6_`, x)
185-
}
186-
187-
roxcpp7_ <- function(x) {
188-
.Call(`_cpp11test_roxcpp7_`, x)
189-
}
190-
191171
cpp11_safe_ <- function(x_sxp) {
192172
.Call(`_cpp11test_cpp11_safe_`, x_sxp)
193173
}

cpp11test/src/cpp11.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,20 @@ extern "C" SEXP _cpp11test_cpp11_insert_(SEXP num_sxp) {
180180
return cpp11::as_sexp(cpp11_insert_(cpp11::as_cpp<cpp11::decay_t<SEXP>>(num_sxp)));
181181
END_CPP11
182182
}
183+
// map.cpp
184+
SEXP ordered_map_to_list_(cpp11::doubles x);
185+
extern "C" SEXP _cpp11test_ordered_map_to_list_(SEXP x) {
186+
BEGIN_CPP11
187+
return cpp11::as_sexp(ordered_map_to_list_(cpp11::as_cpp<cpp11::decay_t<cpp11::doubles>>(x)));
188+
END_CPP11
189+
}
190+
// map.cpp
191+
SEXP unordered_map_to_list_(cpp11::doubles x);
192+
extern "C" SEXP _cpp11test_unordered_map_to_list_(SEXP x) {
193+
BEGIN_CPP11
194+
return cpp11::as_sexp(unordered_map_to_list_(cpp11::as_cpp<cpp11::decay_t<cpp11::doubles>>(x)));
195+
END_CPP11
196+
}
183197
// matrix.cpp
184198
SEXP gibbs_cpp(int N, int thin);
185199
extern "C" SEXP _cpp11test_gibbs_cpp(SEXP N, SEXP thin) {
@@ -620,6 +634,7 @@ static const R_CallMethodDef CallEntries[] = {
620634
{"_cpp11test_my_warning_n1", (DL_FUNC) &_cpp11test_my_warning_n1, 1},
621635
{"_cpp11test_my_warning_n1fmt", (DL_FUNC) &_cpp11test_my_warning_n1fmt, 1},
622636
{"_cpp11test_my_warning_n2fmt", (DL_FUNC) &_cpp11test_my_warning_n2fmt, 2},
637+
{"_cpp11test_ordered_map_to_list_", (DL_FUNC) &_cpp11test_ordered_map_to_list_, 1},
623638
{"_cpp11test_notroxcpp1_", (DL_FUNC) &_cpp11test_notroxcpp1_, 1},
624639
{"_cpp11test_notroxcpp6_", (DL_FUNC) &_cpp11test_notroxcpp6_, 1},
625640
{"_cpp11test_protect_many_", (DL_FUNC) &_cpp11test_protect_many_, 1},
@@ -669,6 +684,7 @@ static const R_CallMethodDef CallEntries[] = {
669684
{"_cpp11test_sum_int_foreach_", (DL_FUNC) &_cpp11test_sum_int_foreach_, 1},
670685
{"_cpp11test_test_destruction_inner", (DL_FUNC) &_cpp11test_test_destruction_inner, 0},
671686
{"_cpp11test_test_destruction_outer", (DL_FUNC) &_cpp11test_test_destruction_outer, 0},
687+
{"_cpp11test_unordered_map_to_list_", (DL_FUNC) &_cpp11test_unordered_map_to_list_, 1},
672688
{"_cpp11test_upper_bound", (DL_FUNC) &_cpp11test_upper_bound, 2},
673689
{"run_testthat_tests", (DL_FUNC) &run_testthat_tests, 1},
674690
{NULL, NULL, 0}

cpp11test/src/map.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include "cpp11/as.hpp"
2+
#include "cpp11/doubles.hpp"
3+
4+
[[cpp11::register]] SEXP ordered_map_to_list_(cpp11::doubles x) {
5+
std::map<double, int> counts;
6+
int n = x.size();
7+
for (int i = 0; i < n; i++) {
8+
counts[x[i]]++;
9+
}
10+
return cpp11::as_sexp(counts);
11+
}
12+
13+
[[cpp11::register]] SEXP unordered_map_to_list_(cpp11::doubles x) {
14+
std::unordered_map<double, int> counts;
15+
int n = x.size();
16+
for (int i = 0; i < n; i++) {
17+
counts[x[i]]++;
18+
}
19+
return cpp11::as_sexp(counts);
20+
}

cpp11test/src/roxygen1.cpp

Lines changed: 0 additions & 22 deletions
This file was deleted.

cpp11test/src/roxygen2.cpp

Lines changed: 0 additions & 28 deletions
This file was deleted.

cpp11test/src/roxygen3.cpp

Lines changed: 0 additions & 38 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
test_that("ordered and unordered C++ maps are converted to R lists", {
2+
set.seed(42L)
3+
x <- rnorm(10L)
4+
xprime <- c(x, x[1])
5+
6+
om <- ordered_map_to_list_(x)
7+
expect_type(om, "list")
8+
9+
om_doubles <- as.double(names(om))
10+
expect_equal(om_doubles, sort(om_doubles))
11+
12+
omprime <- ordered_map_to_list_(xprime)
13+
expect_equal(unlist(unique(omprime)), 1:2)
14+
15+
um <- unordered_map_to_list_(xprime)
16+
expect_type(um, "list")
17+
expect_equal(unlist(unique(um)), 1:2)
18+
})

inst/include/cpp11/as.hpp

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
#include <cmath> // for modf
44
#include <initializer_list> // for initializer_list
5+
#include <map> // for std::map
56
#include <memory> // for std::shared_ptr, std::weak_ptr, std::unique_ptr
67
#include <complex>
78
#include <stdexcept>
8-
#include <string> // for string, basic_string
9-
#include <type_traits> // for decay, enable_if, is_same, is_convertible
9+
#include <string> // for string, basic_string
10+
#include <type_traits> // for decay, enable_if, is_same, is_convertible
11+
#include <unordered_map> // for std::unordered_map
12+
#include <vector> // for std::vector
1013

1114
#include "cpp11/R.hpp" // for SEXP, SEXPREC, Rf_xlength, R_xlen_t
1215
#include "cpp11/protect.hpp" // for stop, protect, safe, protect::function
@@ -277,7 +280,7 @@ enable_if_integral<T, SEXP> as_sexp(const Container& from) {
277280
}
278281

279282
inline SEXP as_sexp(std::initializer_list<int> from) {
280-
return as_sexp<std::initializer_list<int>>(from);
283+
return as_sexp(std::vector<int>(from));
281284
}
282285

283286
template <typename Container, typename T = typename Container::value_type,
@@ -296,7 +299,7 @@ enable_if_floating_point<T, SEXP> as_sexp(const Container& from) {
296299
}
297300

298301
inline SEXP as_sexp(std::initializer_list<double> from) {
299-
return as_sexp<std::initializer_list<double>>(from);
302+
return as_sexp(std::vector<double>(from));
300303
}
301304

302305
template <typename Container, typename T = typename Container::value_type,
@@ -315,7 +318,7 @@ enable_if_bool<T, SEXP> as_sexp(const Container& from) {
315318
}
316319

317320
inline SEXP as_sexp(std::initializer_list<bool> from) {
318-
return as_sexp<std::initializer_list<bool>>(from);
321+
return as_sexp(std::vector<bool>(from));
319322
}
320323

321324
namespace detail {
@@ -361,12 +364,81 @@ enable_if_c_string<T, SEXP> as_sexp(const Container& from) {
361364
}
362365

363366
inline SEXP as_sexp(std::initializer_list<const char*> from) {
364-
return as_sexp<std::initializer_list<const char*>>(from);
367+
return as_sexp(std::vector<const char*>(from));
365368
}
366369

367370
template <typename T, typename = disable_if_r_string<T>>
368371
enable_if_convertible_to_sexp<T, SEXP> as_sexp(const T& from) {
369372
return from;
370373
}
371374

375+
// Pacha: Specialization for std::map
376+
// NOTE: I did not use templates to avoid clashes with doubles/function/etc.
377+
inline SEXP as_sexp(const std::map<std::string, SEXP>& map) {
378+
R_xlen_t size = map.size();
379+
SEXP result = PROTECT(Rf_allocVector(VECSXP, size));
380+
SEXP names = PROTECT(Rf_allocVector(STRSXP, size));
381+
382+
auto it = map.begin();
383+
for (R_xlen_t i = 0; i < size; ++i, ++it) {
384+
SET_VECTOR_ELT(result, i, it->second);
385+
SET_STRING_ELT(names, i, Rf_mkCharCE(it->first.c_str(), CE_UTF8));
386+
}
387+
388+
Rf_setAttrib(result, R_NamesSymbol, names);
389+
UNPROTECT(2);
390+
return result;
391+
}
392+
393+
// Specialization for std::map<double, int>
394+
inline SEXP as_sexp(const std::map<double, int>& map) {
395+
R_xlen_t size = map.size();
396+
SEXP result = PROTECT(Rf_allocVector(VECSXP, size));
397+
SEXP names = PROTECT(Rf_allocVector(REALSXP, size));
398+
399+
auto it = map.begin();
400+
for (R_xlen_t i = 0; i < size; ++i, ++it) {
401+
SET_VECTOR_ELT(result, i, Rf_ScalarInteger(it->second));
402+
REAL(names)[i] = it->first;
403+
}
404+
405+
Rf_setAttrib(result, R_NamesSymbol, names);
406+
UNPROTECT(2);
407+
return result;
408+
}
409+
410+
// Pacha: Specialization for std::unordered_map
411+
inline SEXP as_sexp(const std::unordered_map<std::string, SEXP>& map) {
412+
R_xlen_t size = map.size();
413+
SEXP result = PROTECT(Rf_allocVector(VECSXP, size));
414+
SEXP names = PROTECT(Rf_allocVector(STRSXP, size));
415+
416+
auto it = map.begin();
417+
for (R_xlen_t i = 0; i < size; ++i, ++it) {
418+
SET_VECTOR_ELT(result, i, it->second);
419+
SET_STRING_ELT(names, i, Rf_mkCharCE(it->first.c_str(), CE_UTF8));
420+
}
421+
422+
Rf_setAttrib(result, R_NamesSymbol, names);
423+
UNPROTECT(2);
424+
return result;
425+
}
426+
427+
// Specialization for std::unordered_map<double, int>
428+
inline SEXP as_sexp(const std::unordered_map<double, int>& map) {
429+
R_xlen_t size = map.size();
430+
SEXP result = PROTECT(Rf_allocVector(VECSXP, size));
431+
SEXP names = PROTECT(Rf_allocVector(REALSXP, size));
432+
433+
auto it = map.begin();
434+
for (R_xlen_t i = 0; i < size; ++i, ++it) {
435+
SET_VECTOR_ELT(result, i, Rf_ScalarInteger(it->second));
436+
REAL(names)[i] = it->first;
437+
}
438+
439+
Rf_setAttrib(result, R_NamesSymbol, names);
440+
UNPROTECT(2);
441+
return result;
442+
}
443+
372444
} // namespace cpp11

vignettes/cpp11.Rmd

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -878,8 +878,6 @@ logicals duplicated_cpp(integers x) {
878878
}
879879
```
880880

881-
````{=html}
882-
<!--- TODO: Add `as_sexp()` support for maps
883881
### Map
884882

885883
A map is similar to a set, but instead of storing presence or absence, it can store additional data.
@@ -903,8 +901,6 @@ SEXP table_cpp(doubles x) {
903901
return as_sexp(counts);
904902
}
905903
```
906-
!-->
907-
````
908904

909905
### Exercises
910906

0 commit comments

Comments
 (0)