Skip to content

Commit 70c68df

Browse files
committed
template map to list conversion
1 parent aaed104 commit 70c68df

File tree

5 files changed

+36
-41
lines changed

5 files changed

+36
-41
lines changed

cpp11test/R/cpp11.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ ordered_map_to_list_ <- function(x) {
9292
.Call(`_cpp11test_ordered_map_to_list_`, x)
9393
}
9494

95+
ordered_map_to_list_2_ <- function(x) {
96+
.Call(`_cpp11test_ordered_map_to_list_2_`, x)
97+
}
98+
9599
unordered_map_to_list_ <- function(x) {
96100
.Call(`_cpp11test_unordered_map_to_list_`, x)
97101
}

cpp11test/src/cpp11.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ extern "C" SEXP _cpp11test_ordered_map_to_list_(SEXP x) {
181181
END_CPP11
182182
}
183183
// map.cpp
184+
SEXP ordered_map_to_list_2_(cpp11::doubles x);
185+
extern "C" SEXP _cpp11test_ordered_map_to_list_2_(SEXP x) {
186+
BEGIN_CPP11
187+
return cpp11::as_sexp(ordered_map_to_list_2_(cpp11::as_cpp<cpp11::decay_t<cpp11::doubles>>(x)));
188+
END_CPP11
189+
}
190+
// map.cpp
184191
SEXP unordered_map_to_list_(cpp11::doubles x);
185192
extern "C" SEXP _cpp11test_unordered_map_to_list_(SEXP x) {
186193
BEGIN_CPP11
@@ -515,6 +522,7 @@ static const R_CallMethodDef CallEntries[] = {
515522
{"_cpp11test_my_warning_n1fmt", (DL_FUNC) &_cpp11test_my_warning_n1fmt, 1},
516523
{"_cpp11test_my_warning_n2fmt", (DL_FUNC) &_cpp11test_my_warning_n2fmt, 2},
517524
{"_cpp11test_ordered_map_to_list_", (DL_FUNC) &_cpp11test_ordered_map_to_list_, 1},
525+
{"_cpp11test_ordered_map_to_list_2_", (DL_FUNC) &_cpp11test_ordered_map_to_list_2_, 1},
518526
{"_cpp11test_protect_many_", (DL_FUNC) &_cpp11test_protect_many_, 1},
519527
{"_cpp11test_protect_many_cpp11_", (DL_FUNC) &_cpp11test_protect_many_cpp11_, 1},
520528
{"_cpp11test_protect_many_preserve_", (DL_FUNC) &_cpp11test_protect_many_preserve_, 1},

cpp11test/src/map.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@
1010
return cpp11::as_sexp(counts);
1111
}
1212

13+
[[cpp11::register]] SEXP ordered_map_to_list_2_(cpp11::doubles x) {
14+
std::map<double, double> counts;
15+
double n = x.size();
16+
for (int i = 0; i < n; i++) {
17+
counts[x[i]] += 1.0;
18+
}
19+
return cpp11::as_sexp(counts);
20+
}
21+
1322
[[cpp11::register]] SEXP unordered_map_to_list_(cpp11::doubles x) {
1423
std::unordered_map<double, int> counts;
1524
int n = x.size();

cpp11test/tests/testthat/test-map-to-list.R

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ test_that("ordered and unordered C++ maps are converted to R lists", {
66
om <- ordered_map_to_list_(x)
77
expect_type(om, "list")
88

9+
om2 <- ordered_map_to_list_2_(x)
10+
expect_equal(om, om2)
11+
912
om_doubles <- as.double(names(om))
1013
expect_equal(om_doubles, sort(om_doubles))
1114

inst/include/cpp11/as.hpp

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -336,33 +336,18 @@ enable_if_convertible_to_sexp<T, SEXP> as_sexp(const T& from) {
336336
return from;
337337
}
338338

339-
// Pacha: Specialization for std::map
340-
// NOTE: I did not use templates to avoid clashes with doubles/function/etc.
341-
inline SEXP as_sexp(const std::map<std::string, SEXP>& map) {
342-
R_xlen_t size = map.size();
343-
SEXP result = PROTECT(Rf_allocVector(VECSXP, size));
344-
SEXP names = PROTECT(Rf_allocVector(STRSXP, size));
345-
346-
auto it = map.begin();
347-
for (R_xlen_t i = 0; i < size; ++i, ++it) {
348-
SET_VECTOR_ELT(result, i, it->second);
349-
SET_STRING_ELT(names, i, Rf_mkCharCE(it->first.c_str(), CE_UTF8));
350-
}
351-
352-
Rf_setAttrib(result, R_NamesSymbol, names);
353-
UNPROTECT(2);
354-
return result;
355-
}
356-
357-
// Specialization for std::map<double, int>
358-
inline SEXP as_sexp(const std::map<double, int>& map) {
339+
// Templated specialization for std::map
340+
template <typename Key, typename Value,
341+
typename = enable_if_t<std::is_arithmetic<Key>::value &&
342+
std::is_arithmetic<Value>::value>>
343+
inline SEXP as_sexp(const std::map<Key, Value>& map) {
359344
R_xlen_t size = map.size();
360345
SEXP result = PROTECT(Rf_allocVector(VECSXP, size));
361346
SEXP names = PROTECT(Rf_allocVector(REALSXP, size));
362347

363348
auto it = map.begin();
364349
for (R_xlen_t i = 0; i < size; ++i, ++it) {
365-
SET_VECTOR_ELT(result, i, Rf_ScalarInteger(it->second));
350+
SET_VECTOR_ELT(result, i, as_sexp(it->second));
366351
REAL(names)[i] = it->first;
367352
}
368353

@@ -371,32 +356,18 @@ inline SEXP as_sexp(const std::map<double, int>& map) {
371356
return result;
372357
}
373358

374-
// Pacha: Specialization for std::unordered_map
375-
inline SEXP as_sexp(const std::unordered_map<std::string, SEXP>& map) {
376-
R_xlen_t size = map.size();
377-
SEXP result = PROTECT(Rf_allocVector(VECSXP, size));
378-
SEXP names = PROTECT(Rf_allocVector(STRSXP, size));
379-
380-
auto it = map.begin();
381-
for (R_xlen_t i = 0; i < size; ++i, ++it) {
382-
SET_VECTOR_ELT(result, i, it->second);
383-
SET_STRING_ELT(names, i, Rf_mkCharCE(it->first.c_str(), CE_UTF8));
384-
}
385-
386-
Rf_setAttrib(result, R_NamesSymbol, names);
387-
UNPROTECT(2);
388-
return result;
389-
}
390-
391-
// Specialization for std::unordered_map<double, int>
392-
inline SEXP as_sexp(const std::unordered_map<double, int>& map) {
359+
// Templated specialization for std::unordered_map
360+
template <typename Key, typename Value,
361+
typename = enable_if_t<std::is_arithmetic<Key>::value &&
362+
std::is_arithmetic<Value>::value>>
363+
inline SEXP as_sexp(const std::unordered_map<Key, Value>& map) {
393364
R_xlen_t size = map.size();
394365
SEXP result = PROTECT(Rf_allocVector(VECSXP, size));
395366
SEXP names = PROTECT(Rf_allocVector(REALSXP, size));
396367

397368
auto it = map.begin();
398369
for (R_xlen_t i = 0; i < size; ++i, ++it) {
399-
SET_VECTOR_ELT(result, i, Rf_ScalarInteger(it->second));
370+
SET_VECTOR_ELT(result, i, as_sexp(it->second));
400371
REAL(names)[i] = it->first;
401372
}
402373

0 commit comments

Comments
 (0)