From 2ea819c4ec4962b428504cfc3e7701523718ca9d Mon Sep 17 00:00:00 2001 From: sbearrows Date: Wed, 23 Jun 2021 10:00:18 -0600 Subject: [PATCH 1/6] added empty method for vecs and updated NEWS --- NEWS.md | 1 + cpp11test/src/test-list.cpp | 11 +++++++++++ inst/include/cpp11/r_vector.hpp | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/NEWS.md b/NEWS.md index 17a55d2d..81fe71b8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,7 @@ # cpp11 0.2.7 +* Added empty() and named() methods for r_vector classes, returning true if empty/named (@sbearrows, #182, #186) * Outputting more informative error message when cpp11 decorators are incorrectly formatted (@sbearrows, #127) * Fix spurious diffs from `tools::package_native_routine_registration_skeleton()` by temporarily using C collation (@sbearrows, #171) * Fix a transient memory leak for functions that return values from `cpp11::unwind_protect()` and `cpp11::safe` (#154) diff --git a/cpp11test/src/test-list.cpp b/cpp11test/src/test-list.cpp index d856e8b8..98fdf1cc 100644 --- a/cpp11test/src/test-list.cpp +++ b/cpp11test/src/test-list.cpp @@ -126,4 +126,15 @@ context("list-C++") { expect_true(first[0] == 1); expect_true(first[1] == 2); } + + test_that("empty() works") { + cpp11::writable::list x; + + expect_true(x.empty()); + + cpp11::writable::list y(1); + + expect_false(y.empty()); + } + } diff --git a/inst/include/cpp11/r_vector.hpp b/inst/include/cpp11/r_vector.hpp index 3d9afdd9..3886a745 100644 --- a/inst/include/cpp11/r_vector.hpp +++ b/inst/include/cpp11/r_vector.hpp @@ -112,6 +112,8 @@ class r_vector { operator sexp() const; + bool empty() const; + /// Provide access to the underlying data, mainly for interface /// compatibility with std::vector SEXP data() const; @@ -394,6 +396,12 @@ inline r_vector::operator sexp() const { return data_; } +template +inline bool r_vector::empty() const { + return (!(this->size() > 0)); +} + + /// Provide access to the underlying data, mainly for interface /// compatibility with std::vector template From 57beaacc19f75ed2fb570003cc69ed1f518f64f0 Mon Sep 17 00:00:00 2001 From: sbearrows Date: Wed, 23 Jun 2021 10:15:52 -0600 Subject: [PATCH 2/6] didnt mean to make changes --- NEWS.md | 1 - cpp11test/src/test-list.cpp | 11 ----------- inst/include/cpp11/r_vector.hpp | 7 ------- 3 files changed, 19 deletions(-) diff --git a/NEWS.md b/NEWS.md index 81fe71b8..17a55d2d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,7 +5,6 @@ # cpp11 0.2.7 -* Added empty() and named() methods for r_vector classes, returning true if empty/named (@sbearrows, #182, #186) * Outputting more informative error message when cpp11 decorators are incorrectly formatted (@sbearrows, #127) * Fix spurious diffs from `tools::package_native_routine_registration_skeleton()` by temporarily using C collation (@sbearrows, #171) * Fix a transient memory leak for functions that return values from `cpp11::unwind_protect()` and `cpp11::safe` (#154) diff --git a/cpp11test/src/test-list.cpp b/cpp11test/src/test-list.cpp index 98fdf1cc..d856e8b8 100644 --- a/cpp11test/src/test-list.cpp +++ b/cpp11test/src/test-list.cpp @@ -126,15 +126,4 @@ context("list-C++") { expect_true(first[0] == 1); expect_true(first[1] == 2); } - - test_that("empty() works") { - cpp11::writable::list x; - - expect_true(x.empty()); - - cpp11::writable::list y(1); - - expect_false(y.empty()); - } - } diff --git a/inst/include/cpp11/r_vector.hpp b/inst/include/cpp11/r_vector.hpp index 3886a745..1bcaafb7 100644 --- a/inst/include/cpp11/r_vector.hpp +++ b/inst/include/cpp11/r_vector.hpp @@ -112,8 +112,6 @@ class r_vector { operator sexp() const; - bool empty() const; - /// Provide access to the underlying data, mainly for interface /// compatibility with std::vector SEXP data() const; @@ -396,11 +394,6 @@ inline r_vector::operator sexp() const { return data_; } -template -inline bool r_vector::empty() const { - return (!(this->size() > 0)); -} - /// Provide access to the underlying data, mainly for interface /// compatibility with std::vector From c8b1c8b922117872cab2e6b884dedd3b24938644 Mon Sep 17 00:00:00 2001 From: sbearrows Date: Thu, 8 Jul 2021 16:58:48 -0600 Subject: [PATCH 3/6] as_int as_double ready for review --- NEWS.md | 1 + cpp11test/src/test-doubles.cpp | 20 ++++++++++++++++++++ cpp11test/src/test-integers.cpp | 32 ++++++++++++++++++++++++++++++++ inst/include/cpp11/doubles.hpp | 21 +++++++++++++++++++++ inst/include/cpp11/integers.hpp | 26 ++++++++++++++++++++++++++ 5 files changed, 100 insertions(+) diff --git a/NEWS.md b/NEWS.md index 829eb29c..87acfe27 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,5 @@ # cpp11 (development version) +* added `as_double()` and `as_integer()` method to coerce integers to doubles and doubles to integers to doubles (@sbearrows, #46) # cpp11 0.3.1 diff --git a/cpp11test/src/test-doubles.cpp b/cpp11test/src/test-doubles.cpp index a5f58aee..46eadbd0 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,25 @@ context("doubles-C++") { expect_true(cpp11::is_na(y)); } + test_that("as_double(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_double(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_double(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..c5ca5eed 100644 --- a/cpp11test/src/test-integers.cpp +++ b/cpp11test/src/test-integers.cpp @@ -1,8 +1,40 @@ #include #include "Rversion.h" +#include "cpp11/doubles.hpp" #include "cpp11/integers.hpp" +#include "cpp11/strings.hpp" context("integers-C++") { + test_that("as_integer(doubles)") { + // TYPEOF(x) == INTSXP + cpp11::writable::doubles y; + y.push_back(10.00); + cpp11::writable::integers i(cpp11::as_integer(y)); + expect_true(i[0] == 10); + expect_true(TYPEOF(i) == INTSXP); + + cpp11::writable::doubles x; + x.push_back(10.01); + expect_error(cpp11::as_integer(x)); + + cpp11::writable::strings e; + e.push_back("a"); + e.push_back("b"); + expect_error(cpp11::as_integer(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_integer(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..6e11f002 100644 --- a/inst/include/cpp11/doubles.hpp +++ b/inst/include/cpp11/doubles.hpp @@ -131,6 +131,27 @@ typedef r_vector doubles; } // namespace writable +typedef r_vector integers; + +inline doubles as_double(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; + } + + // else + stop("Expected a numeric vector for"); +} + template <> inline double na() { return NA_REAL; diff --git a/inst/include/cpp11/integers.hpp b/inst/include/cpp11/integers.hpp index b063984d..28808a02 100644 --- a/inst/include/cpp11/integers.hpp +++ b/inst/include/cpp11/integers.hpp @@ -141,4 +141,30 @@ inline int na() { return NA_INTEGER; } +// forward declaration + +typedef r_vector doubles; + +inline integers as_integer(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)) { + stop("All elements must be integer-like"); + } + ret[i] = (static_cast(el)); + } + + return ret; + } + + // else + stop("Expected a numeric vector"); +} + } // namespace cpp11 From d8a97be651542fff6d2f4beebb0e59723f95452d Mon Sep 17 00:00:00 2001 From: sbearrows Date: Fri, 9 Jul 2021 09:45:52 -0600 Subject: [PATCH 4/6] format error --- inst/include/cpp11/r_vector.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/inst/include/cpp11/r_vector.hpp b/inst/include/cpp11/r_vector.hpp index 5db8109e..4b8b8a29 100644 --- a/inst/include/cpp11/r_vector.hpp +++ b/inst/include/cpp11/r_vector.hpp @@ -406,7 +406,6 @@ inline r_vector::operator sexp() const { return data_; } - /// Provide access to the underlying data, mainly for interface /// compatibility with std::vector template From 61cf3d45f4fddb0550107b8c8bf248aa46d8e858 Mon Sep 17 00:00:00 2001 From: Jim Hester Date: Fri, 9 Jul 2021 13:36:31 -0400 Subject: [PATCH 5/6] Throw regular C++ exceptions rather than relying on cpp11::stop() --- cpp11test/src/test-doubles.cpp | 1 + cpp11test/src/test-integers.cpp | 1 + inst/include/cpp11/doubles.hpp | 3 +-- inst/include/cpp11/integers.hpp | 5 ++--- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp11test/src/test-doubles.cpp b/cpp11test/src/test-doubles.cpp index 46eadbd0..cfefa33c 100644 --- a/cpp11test/src/test-doubles.cpp +++ b/cpp11test/src/test-doubles.cpp @@ -367,6 +367,7 @@ context("doubles-C++") { y.push_back(124); y.push_back(899); cpp11::doubles i(cpp11::as_double(y)); + expect_true(i[0] == 10); expect_true(i[1] == 13616); expect_true(i[2] == 124); diff --git a/cpp11test/src/test-integers.cpp b/cpp11test/src/test-integers.cpp index c5ca5eed..20c4f173 100644 --- a/cpp11test/src/test-integers.cpp +++ b/cpp11test/src/test-integers.cpp @@ -35,6 +35,7 @@ context("integers-C++") { 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 6e11f002..488b21ad 100644 --- a/inst/include/cpp11/doubles.hpp +++ b/inst/include/cpp11/doubles.hpp @@ -148,8 +148,7 @@ inline doubles as_double(sexp x) { return ret; } - // else - stop("Expected a numeric vector for"); + throw type_error(INTSXP, TYPEOF(x)); } template <> diff --git a/inst/include/cpp11/integers.hpp b/inst/include/cpp11/integers.hpp index 28808a02..43097d35 100644 --- a/inst/include/cpp11/integers.hpp +++ b/inst/include/cpp11/integers.hpp @@ -155,7 +155,7 @@ inline integers as_integer(sexp x) { for (size_t i = 0; i < len; ++i) { double el = xn[i]; if (!is_convertable_without_loss_to_integer(el)) { - stop("All elements must be integer-like"); + throw std::runtime_error("All elements must be integer-like"); } ret[i] = (static_cast(el)); } @@ -163,8 +163,7 @@ inline integers as_integer(sexp x) { return ret; } - // else - stop("Expected a numeric vector"); + throw type_error(REALSXP, TYPEOF(x)); } } // namespace cpp11 From e39f74944a881e5c4d528712367db02accd7d69f Mon Sep 17 00:00:00 2001 From: sbearrows Date: Fri, 9 Jul 2021 11:42:22 -0600 Subject: [PATCH 6/6] changed names --- cpp11test/src/test-doubles.cpp | 6 +++--- cpp11test/src/test-integers.cpp | 10 +++++----- inst/include/cpp11/doubles.hpp | 2 +- inst/include/cpp11/integers.hpp | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp11test/src/test-doubles.cpp b/cpp11test/src/test-doubles.cpp index 46eadbd0..5ae7926b 100644 --- a/cpp11test/src/test-doubles.cpp +++ b/cpp11test/src/test-doubles.cpp @@ -360,13 +360,13 @@ context("doubles-C++") { expect_true(cpp11::is_na(y)); } - test_that("as_double(integers)") { + 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_double(y)); + cpp11::doubles i(cpp11::as_doubles(y)); expect_true(i[0] == 10); expect_true(i[1] == 13616); expect_true(i[2] == 124); @@ -376,7 +376,7 @@ context("doubles-C++") { cpp11::writable::strings e; e.push_back("a"); e.push_back("b"); - expect_error(cpp11::as_double(e)); + expect_error(cpp11::as_doubles(e)); } test_that("doubles operator[] and at") { diff --git a/cpp11test/src/test-integers.cpp b/cpp11test/src/test-integers.cpp index c5ca5eed..11e5df8d 100644 --- a/cpp11test/src/test-integers.cpp +++ b/cpp11test/src/test-integers.cpp @@ -5,22 +5,22 @@ #include "cpp11/strings.hpp" context("integers-C++") { - test_that("as_integer(doubles)") { + test_that("as_integers(doubles)") { // TYPEOF(x) == INTSXP cpp11::writable::doubles y; y.push_back(10.00); - cpp11::writable::integers i(cpp11::as_integer(y)); + 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_integer(x)); + expect_error(cpp11::as_integers(x)); cpp11::writable::strings e; e.push_back("a"); e.push_back("b"); - expect_error(cpp11::as_integer(e)); + expect_error(cpp11::as_integers(e)); cpp11::writable::doubles z; z.push_back(10); @@ -28,7 +28,7 @@ context("integers-C++") { z.push_back(100000); z.push_back(100000.00); - cpp11::writable::integers t((cpp11::as_integer(z))); + cpp11::writable::integers t((cpp11::as_integers(z))); expect_true(t[0] == 10); expect_true(t[1] == 1000); expect_true(t[2] == 100000); diff --git a/inst/include/cpp11/doubles.hpp b/inst/include/cpp11/doubles.hpp index 6e11f002..4f735a2c 100644 --- a/inst/include/cpp11/doubles.hpp +++ b/inst/include/cpp11/doubles.hpp @@ -133,7 +133,7 @@ typedef r_vector doubles; typedef r_vector integers; -inline doubles as_double(sexp x) { +inline doubles as_doubles(sexp x) { if (TYPEOF(x) == REALSXP) { return as_cpp(x); } diff --git a/inst/include/cpp11/integers.hpp b/inst/include/cpp11/integers.hpp index 28808a02..b8da026b 100644 --- a/inst/include/cpp11/integers.hpp +++ b/inst/include/cpp11/integers.hpp @@ -145,7 +145,7 @@ inline int na() { typedef r_vector doubles; -inline integers as_integer(sexp x) { +inline integers as_integers(sexp x) { if (TYPEOF(x) == INTSXP) { return as_cpp(x); } else if (TYPEOF(x) == REALSXP) {