Skip to content
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
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
21 changes: 21 additions & 0 deletions cpp11test/src/test-doubles.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <testthat.h>
#include <cstring>
#include "cpp11/doubles.hpp"
#include "cpp11/integers.hpp"
#include "cpp11/sexp.hpp"
#include "cpp11/strings.hpp"

Expand Down Expand Up @@ -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;
Expand Down
33 changes: 33 additions & 0 deletions cpp11test/src/test-integers.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,41 @@
#include <testthat.h>
#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);
Expand Down
20 changes: 20 additions & 0 deletions inst/include/cpp11/doubles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,26 @@ typedef r_vector<double> doubles;

} // namespace writable

typedef r_vector<int> integers;

inline doubles as_doubles(sexp x) {
if (TYPEOF(x) == REALSXP) {
return as_cpp<doubles>(x);
}

else if (TYPEOF(x) == INTSXP) {
integers xn = as_cpp<integers>(x);
size_t len = xn.size();
writable::doubles ret;
for (size_t i = 0; i < len; ++i) {
ret.push_back(static_cast<double>(xn[i]));
}
return ret;
}

throw type_error(INTSXP, TYPEOF(x));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cpp11 defines a type_error class to generate a more informative error message for type issues, so we can use that here.

class type_error : public std::exception {
public:
type_error(int expected, int actual) : expected_(expected), actual_(actual) {}
virtual const char* what() const noexcept {
snprintf(str_, 64, "Invalid input type, expected '%s' actual '%s'",
Rf_type2char(expected_), Rf_type2char(actual_));
return str_;
}
private:
int expected_;
int actual_;
mutable char str_[64];
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay awesome thank you!

}

template <>
inline double na() {
return NA_REAL;
Expand Down
25 changes: 25 additions & 0 deletions inst/include/cpp11/integers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,29 @@ inline int na() {
return NA_INTEGER;
}

// forward declaration

typedef r_vector<double> doubles;

inline integers as_integers(sexp x) {
if (TYPEOF(x) == INTSXP) {
return as_cpp<integers>(x);
} else if (TYPEOF(x) == REALSXP) {
doubles xn = as_cpp<doubles>(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<int>(el));
}

return ret;
}

throw type_error(REALSXP, TYPEOF(x));
}

} // namespace cpp11