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
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# cpp11 (development version)

* Added the missing implementation for `x.at("name")` for read only vectors
(#370).

* Constructors for writable vectors from `initializer_list<named_arg>` now
check that `named_arg` contains a length 1 object of the correct type, and
throws either a `cpp11::type_error` or `std::length_error` if that is not the
Expand Down
20 changes: 14 additions & 6 deletions cpp11test/src/test-doubles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,13 +495,21 @@ context("doubles-C++") {
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(x["a"] == 1.);
expect_true(x["b"] == 2.);
expect_error(x["c"]);

expect_true(x.at("a") == 1.);
expect_true(x.at("b") == 2.);
expect_error(x.at("c"));

expect_true(y["a"] == 1.);
expect_true(y["b"] == 2.);
expect_error(y["c"]);

expect_true(y["a"] == 1);
expect_true(y["b"] == 2);
expect_error(y["c"] == 2);
expect_true(y.at("a") == 1.);
expect_true(y.at("b") == 2.);
expect_error(y.at("c"));
}

test_that("doubles::find") {
Expand Down
14 changes: 11 additions & 3 deletions cpp11test/src/test-integers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,18 +250,26 @@ context("integers-C++") {
}
#endif

test_that("operator[] with names") {
test_that("operator[] and at with names") {
using namespace cpp11::literals;
cpp11::writable::integers x({"a"_nm = 1, "b"_nm = 2});
cpp11::integers y(x);

expect_true(x["a"] == 1);
expect_true(x["b"] == 2);
expect_error(x["c"] == 2);
expect_error(x["c"]);

expect_true(x.at("a") == 1);
expect_true(x.at("b") == 2);
expect_error(x.at("c"));

expect_true(y["a"] == 1);
expect_true(y["b"] == 2);
expect_error(y["c"] == 2);
expect_error(y["c"]);

expect_true(y.at("a") == 1);
expect_true(y.at("b") == 2);
expect_error(y.at("c"));
}

test_that("is_na(integer)") {
Expand Down
4 changes: 3 additions & 1 deletion cpp11test/src/test-list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ context("list-C++") {
expect_true(x.size() == nms.size());
}

test_that("list::operator[] by name") {
test_that("list::operator[] and at by name") {
SEXP x = PROTECT(Rf_allocVector(VECSXP, 1));

SEXP elt = Rf_allocVector(INTSXP, 1);
Expand All @@ -183,9 +183,11 @@ context("list-C++") {

expect_true(lst.named());
expect_true(lst["name"] == elt);
expect_true(lst.at("name") == elt);

// Lists are the only class where OOB accesses by name return `NULL`
expect_true(lst["oob"] == R_NilValue);
expect_true(lst.at("oob") == R_NilValue);

UNPROTECT(1);
}
Expand Down
5 changes: 5 additions & 0 deletions inst/include/cpp11/r_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,11 @@ inline T r_vector<T>::at(const size_type pos) const {
return at(static_cast<R_xlen_t>(pos));
}

template <typename T>
inline T r_vector<T>::at(const r_string& name) const {
return operator[](name);
}

template <typename T>
inline bool r_vector<T>::contains(const r_string& name) const {
SEXP names = this->names();
Expand Down