diff --git a/NEWS.md b/NEWS.md index d8fca332..2f2005f6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,9 @@ # cpp11 (development version) +* added `as_double()` and `as_integer()` method to coerce integers to doubles and doubles to integers to doubles (@sbearrows, #46) * Removed redundant `.Call calls` in cpp11.cpp file (@sbearrows, #170) * Allow cpp11 decorators of the form `cpp11::linking_to` (@sbearrows, #193) + # cpp11 0.3.1 * Fix stringop-truncation warning from generated wrapping code. diff --git a/cpp11test/src/test-doubles.cpp b/cpp11test/src/test-doubles.cpp index a5f58aee..7a4274ac 100644 --- a/cpp11test/src/test-doubles.cpp +++ b/cpp11test/src/test-doubles.cpp @@ -1,6 +1,7 @@ #include #include #include "cpp11/doubles.hpp" +#include "cpp11/integers.hpp" #include "cpp11/sexp.hpp" #include "cpp11/strings.hpp" @@ -359,6 +360,26 @@ context("doubles-C++") { expect_true(cpp11::is_na(y)); } + test_that("as_doubles(integers)") { + cpp11::writable::integers y; + y.push_back(10); + y.push_back(13616); + y.push_back(124); + y.push_back(899); + cpp11::doubles i(cpp11::as_doubles(y)); + + expect_true(i[0] == 10); + expect_true(i[1] == 13616); + expect_true(i[2] == 124); + expect_true(i[3] == 899); + expect_true(TYPEOF(i) == REALSXP); + + cpp11::writable::strings e; + e.push_back("a"); + e.push_back("b"); + expect_error(cpp11::as_doubles(e)); + } + test_that("doubles operator[] and at") { cpp11::doubles x(Rf_allocVector(REALSXP, 2)); REAL(x)[0] = 1; diff --git a/cpp11test/src/test-integers.cpp b/cpp11test/src/test-integers.cpp index b875bbaf..0fbf10af 100644 --- a/cpp11test/src/test-integers.cpp +++ b/cpp11test/src/test-integers.cpp @@ -1,8 +1,41 @@ #include #include "Rversion.h" +#include "cpp11/doubles.hpp" #include "cpp11/integers.hpp" +#include "cpp11/strings.hpp" context("integers-C++") { + test_that("as_integers(doubles)") { + // TYPEOF(x) == INTSXP + cpp11::writable::doubles y; + y.push_back(10.00); + cpp11::writable::integers i(cpp11::as_integers(y)); + expect_true(i[0] == 10); + expect_true(TYPEOF(i) == INTSXP); + + cpp11::writable::doubles x; + x.push_back(10.01); + expect_error(cpp11::as_integers(x)); + + cpp11::writable::strings e; + e.push_back("a"); + e.push_back("b"); + expect_error(cpp11::as_integers(e)); + + cpp11::writable::doubles z; + z.push_back(10); + z.push_back(1000); + z.push_back(100000); + z.push_back(100000.00); + + cpp11::writable::integers t((cpp11::as_integers(z))); + expect_true(t[0] == 10); + expect_true(t[1] == 1000); + expect_true(t[2] == 100000); + expect_true(t[3] == 100000); + expect_true(TYPEOF(t) == INTSXP); + } + test_that("integers.push_back()") { cpp11::writable::integers x; x.push_back(1); diff --git a/inst/include/cpp11/doubles.hpp b/inst/include/cpp11/doubles.hpp index 2d5ea9f2..388e8a65 100644 --- a/inst/include/cpp11/doubles.hpp +++ b/inst/include/cpp11/doubles.hpp @@ -131,6 +131,26 @@ typedef r_vector doubles; } // namespace writable +typedef r_vector integers; + +inline doubles as_doubles(sexp x) { + if (TYPEOF(x) == REALSXP) { + return as_cpp(x); + } + + else if (TYPEOF(x) == INTSXP) { + integers xn = as_cpp(x); + size_t len = xn.size(); + writable::doubles ret; + for (size_t i = 0; i < len; ++i) { + ret.push_back(static_cast(xn[i])); + } + return ret; + } + + throw type_error(INTSXP, TYPEOF(x)); +} + template <> inline double na() { return NA_REAL; diff --git a/inst/include/cpp11/integers.hpp b/inst/include/cpp11/integers.hpp index b063984d..d8d5cf7c 100644 --- a/inst/include/cpp11/integers.hpp +++ b/inst/include/cpp11/integers.hpp @@ -141,4 +141,29 @@ inline int na() { return NA_INTEGER; } +// forward declaration + +typedef r_vector doubles; + +inline integers as_integers(sexp x) { + if (TYPEOF(x) == INTSXP) { + return as_cpp(x); + } else if (TYPEOF(x) == REALSXP) { + doubles xn = as_cpp(x); + size_t len = (xn.size()); + writable::integers ret = writable::integers(len); + for (size_t i = 0; i < len; ++i) { + double el = xn[i]; + if (!is_convertable_without_loss_to_integer(el)) { + throw std::runtime_error("All elements must be integer-like"); + } + ret[i] = (static_cast(el)); + } + + return ret; + } + + throw type_error(REALSXP, TYPEOF(x)); +} + } // namespace cpp11