#include
#include
#include "cpp11/doubles.hpp"
#include "cpp11/sexp.hpp"
#include "cpp11/strings.hpp"
context("doubles-C++") {
test_that("doubles::r_vector(SEXP)") {
cpp11::doubles x(Rf_allocVector(REALSXP, 2));
expect_true(x.size() == 2);
expect_error(cpp11::doubles(Rf_allocVector(INTSXP, 2)));
}
test_that("doubles::r_vector::const_iterator()") {
cpp11::doubles x(Rf_allocVector(REALSXP, 100));
REAL(x)[0] = 1;
REAL(x)[1] = 2;
REAL(x)[2] = 3;
REAL(x)[3] = 4;
REAL(x)[4] = 5;
REAL(x)[97] = 98;
REAL(x)[98] = 99;
REAL(x)[99] = 100;
expect_true(x.size() == 100);
auto it = x.begin();
auto it2 = x.begin();
expect_true(it == it2);
++it;
expect_true(!(it == it2));
expect_true(it != it2);
++it;
expect_true(*it == 3);
--it;
expect_true(*it == 2);
--it;
it += 99;
expect_true(*it == 100);
--it;
expect_true(*it == 99);
--it;
expect_true(*it == 98);
it -= 95;
expect_true(*it == 3);
}
test_that("doubles.push_back()") {
cpp11::writable::doubles x;
x.push_back(1);
x.push_back(2);
expect_true(x.size() == 2);
expect_true(x[0] == 1);
expect_true(x[1] == 2);
}
test_that("doubles.resize()") {
cpp11::writable::doubles x;
x.resize(2);
x[0] = 1;
x[1] = 2;
expect_true(x.size() == 2);
expect_true(x[0] == 1);
expect_true(x[1] == 2);
}
test_that("doubles.at()") {
cpp11::writable::doubles x;
expect_error(x.at(-1));
expect_error(x.at(0));
x.push_back(1);
expect_true(x.at(0) == 1);
expect_error(x.at(1));
}
test_that("doubles.pop_back()") {
cpp11::writable::doubles x;
x.push_back(1);
x.push_back(2);
x.pop_back();
expect_true(x.size() == 1);
expect_true(x[0] == 1);
expect_error(x.at(1));
}
test_that("doubles.insert()") {
cpp11::writable::doubles x;
x.insert(0, 1);
x.insert(0, 2);
x.insert(1, 3);
expect_true(x.size() == 3);
expect_true(x[0] == 2);
expect_true(x[1] == 3);
expect_true(x[2] == 1);
}
test_that("doubles.erase()") {
cpp11::writable::doubles x;
x.push_back(1);
x.push_back(2);
x.push_back(3);
x.push_back(4);
x.push_back(5);
expect_true(x.size() == 5);
x.erase(0);
expect_true(x.size() == 4);
expect_true(x[0] == 2);
expect_true(x[1] == 3);
expect_true(x[2] == 4);
expect_true(x[3] == 5);
x.erase(2);
expect_true(x.size() == 3);
expect_true(x[0] == 2);
expect_true(x[1] == 3);
expect_true(x[2] == 5);
}
test_that("doubles.iterator* = ") {
cpp11::writable::doubles x;
x.push_back(1);
x.push_back(2);
x.push_back(3);
auto it = x.begin() + 1;
*it = 3;
++it;
*it = 4;
expect_true(x.size() == 3);
expect_true(x[0] == 1);
expect_true(x[1] == 3);
expect_true(x[2] == 4);
}
test_that("writable::doubles(SEXP)") {
SEXP x = PROTECT(Rf_allocVector(REALSXP, 5));
REAL(x)[0] = 1;
REAL(x)[1] = 2;
REAL(x)[2] = 3;
REAL(x)[3] = 4;
REAL(x)[4] = 5;
cpp11::writable::doubles y(x);
y[0] = -1;
expect_true(x != y.data());
expect_true(REAL(x)[0] == 1);
expect_true(y[0] == -1);
cpp11::writable::doubles z(y);
z[0] = -2;
expect_true(z.data() != y.data());
expect_true(REAL(x)[0] == 1);
expect_true(y[0] == -1);
expect_true(z[0] == -2);
UNPROTECT(1);
}
test_that("writable::doubles(SEXP, bool)") {
SEXP x = PROTECT(Rf_ScalarReal(5.));
cpp11::writable::doubles y(x, false);
expect_true(REAL(y)[0] == 5.);
UNPROTECT(1);
}
#if defined(__APPLE__) && defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0)
test_that("writable::doubles(ALTREP_SEXP)") {
SEXP x = PROTECT(Rf_coerceVector(R_compact_intrange(1, 5), REALSXP));
// Need to find (or create) an altrep class that implements duplicate.
cpp11::writable::doubles y(x);
y[0] = -1;
expect_true(x != y.data());
expect_true(REAL_ELT(x, 0) == 1);
expect_true(y[0] == -1);
cpp11::writable::doubles z(y);
z[0] = -2;
expect_true(z.data() != y.data());
expect_true(REAL_ELT(x, 0) == 1);
expect_true(y[0] == -1);
expect_true(z[0] == -2);
z.push_back(6);
expect_true(z[5] == 6);
UNPROTECT(1);
}
test_that("writable::doubles(SEXP) assignment") {
cpp11::writable::doubles x({1., 2., 3.});
cpp11::writable::doubles y({0.});
y = x;
expect_true(y.size() == 3);
expect_true(y.data() != x.data());
expect_true(y.is_altrep() == x.is_altrep());
cpp11::writable::doubles z(Rf_coerceVector(R_compact_intrange(1, 5), REALSXP));
cpp11::writable::doubles w({0.});
w = z;
expect_true(w.size() == 5);
expect_true(w.data() != z.data());
expect_true(w.is_altrep() == z.is_altrep());
}
test_that("writable::doubles(SEXP) move assignment") {
cpp11::writable::doubles x({1., 2., 3.});
cpp11::writable::doubles y({0.});
auto x_data = x.data();
y = std::move(x);
expect_true(y.size() == 3);
expect_true(y.data() == x_data);
expect_true(y.is_altrep() == false);
cpp11::writable::doubles z(Rf_coerceVector(R_compact_intrange(1, 5), REALSXP));
cpp11::writable::doubles w({0.});
expect_true(z.is_altrep() == true);
auto z_data = z.data();
w = std::move(z);
expect_true(w.size() == 5);
expect_true(w.data() == z_data);
expect_true(w.is_altrep() == true);
}
#endif
test_that("doubles::names(empty)") {
cpp11::doubles x;
auto nms = x.names();
expect_true(nms.size() == 0);
}
test_that("doubles::names") {
using namespace cpp11::literals;
cpp11::writable::doubles x({"a"_nm = 1., "b"_nm = 2.});
expect_true(x[0] == 1.);
expect_true(x[1] == 2.);
expect_true(x.contains("a"));
expect_true(!x.contains("c"));
expect_true(x["a"] == 1.);
expect_true(x["b"] == 2.);
cpp11::sexp nms(x.names());
expect_true(Rf_xlength(nms) == 2);
auto nms0 = CHAR(STRING_ELT(nms, 0));
auto nms1 = CHAR(STRING_ELT(nms, 1));
expect_true(strcmp(nms0, "a") == 0);
expect_true(strcmp(nms1, "b") == 0);
}
test_that("doubles::attr") {
cpp11::doubles x(PROTECT(Rf_allocVector(REALSXP, 2)));
REAL(x)[0] = 1;
REAL(x)[1] = 2;
SEXP foo = Rf_install("foo");
Rf_setAttrib(x, foo, Rf_mkString("bar"));
// This doesn't compile by design
// x.attr("foo") = "bar";
// But this will
cpp11::writable::doubles y(x);
y.attr("foo") = "baz";
expect_true(strcmp(CHAR(STRING_ELT(x.attr("foo"), 0)), "bar") == 0);
expect_true(strcmp(CHAR(STRING_ELT(y.attr("foo"), 0)), "baz") == 0);
UNPROTECT(1);
}
test_that("writable::doubles(std::vector::iterator)") {
std::vector x({1, 2, 3, 4, 5});
cpp11::writable::doubles y(x.begin(), x.end());
expect_true(y.size() == 5);
expect_true(y[0] == 1);
expect_true(y[4] == 5);
}
test_that("writable::doubles(std::vector)") {
std::vector x({1, 2, 3, 4, 5});
cpp11::writable::doubles y(x);
expect_true(y.size() == 5);
expect_true(y[0] == 1);
expect_true(y[4] == 5);
}
test_that("writable::doubles attributes are kept when converted to doubles") {
cpp11::writable::doubles x({1, 2});
x.names() = {"a", "b"};
cpp11::strings x_nms(x.names());
expect_true(x_nms[0] == "a");
expect_true(x_nms[1] == "b");
cpp11::doubles y(x);
cpp11::strings y_nms(y.names());
expect_true(y_nms[0] == "a");
expect_true(y_nms[1] == "b");
}
test_that("comparison operator works") {
using namespace cpp11;
cpp11::doubles base(Rf_allocVector(REALSXP, 2));
cpp11::doubles same_values(Rf_allocVector(REALSXP, 2));
cpp11::doubles diff_length(Rf_allocVector(REALSXP, 1));
cpp11::doubles diff_values(Rf_allocVector(REALSXP, 2));
REAL(base)[0] = 1;
REAL(base)[1] = 2;
REAL(same_values)[0] = 1;
REAL(same_values)[1] = 2;
REAL(diff_length)[0] = 1;
REAL(diff_values)[0] = 1;
REAL(diff_values)[1] = 3;
expect_true(base == base);
expect_true(base == same_values);
expect_true(!(base == diff_length));
expect_true(!(base == diff_values));
expect_true(!(base != base));
expect_true(!(base != same_values));
expect_true(base != diff_length);
expect_true(base != diff_values);
}
test_that("is_na(double)") {
double x = 0.;
expect_true(!cpp11::is_na(x));
double y = NA_REAL;
expect_true(cpp11::is_na(y));
}
test_that("doubles operator[] and at") {
cpp11::doubles x(Rf_allocVector(REALSXP, 2));
REAL(x)[0] = 1;
REAL(x)[1] = 2;
int i0 = 0;
R_xlen_t x0 = 0;
size_t s0 = 0;
expect_true(x[i0] == 1);
expect_true(x[x0] == 1);
expect_true(x[s0] == 1);
expect_true(x.at(i0) == 1);
expect_true(x.at(x0) == 1);
expect_true(x.at(s0) == 1);
}
test_that("writable::doubles operator[] and at") {
cpp11::writable::doubles x(Rf_allocVector(REALSXP, 2));
REAL(x)[0] = 1;
REAL(x)[1] = 2;
int i0 = 0;
R_xlen_t x0 = 0;
size_t s0 = 0;
expect_true(x[i0] == 1);
expect_true(x[x0] == 1);
expect_true(x[s0] == 1);
expect_true(x.at(i0) == 1);
expect_true(x.at(x0) == 1);
expect_true(x.at(s0) == 1);
}
test_that("operator[] and at with names") {
using namespace cpp11::literals;
cpp11::writable::doubles x({"a"_nm = 1., "b"_nm = 2.});
cpp11::doubles y(x);
expect_true(x["a"] == 1);
expect_true(x["b"] == 2);
expect_error(x["c"] == 2);
expect_true(y["a"] == 1);
expect_true(y["b"] == 2);
expect_error(y["c"] == 2);
}
test_that("doubles::find") {
using namespace cpp11::literals;
cpp11::writable::doubles x({"a"_nm = 1., "b"_nm = 2.});
cpp11::doubles y(x);
expect_true(x.find("a") == x.begin());
expect_true(x.find("b") == x.begin() + 1);
expect_true(x.find("c") == x.end());
expect_true(y.find("a") == y.begin());
expect_true(y.find("b") == y.begin() + 1);
expect_true(y.find("c") == y.end());
}
test_that("writable::doubles compound assignments") {
cpp11::writable::doubles x(Rf_allocVector(REALSXP, 1));
REAL(x)[0] = 1;
auto x0 = x[0];
expect_true(x0 == 1);
x0 += 3;
expect_true(x0 == 4);
x0 -= 2;
expect_true(x0 == 2);
x0 *= 2;
expect_true(x0 == 4);
x0 /= 2;
expect_true(x0 == 2);
x0--;
expect_true(x0 == 1);
x0++;
expect_true(x0 == 2);
++x0;
expect_true(x0 == 3);
--x0;
expect_true(x0 == 2);
}
test_that("writable::doubles convert to doubles with correct size (#128)") {
cpp11::writable::doubles foo;
foo.push_back(1.);
foo.push_back(2.);
foo.push_back(3.);
cpp11::doubles bar(foo);
expect_true(Rf_xlength(bar) == 3);
}
}