Skip to content

Commit 6df9fb5

Browse files
authored
Unify OOB behavior rather than duplicating method (#381)
1 parent 254277b commit 6df9fb5

File tree

4 files changed

+49
-14
lines changed

4 files changed

+49
-14
lines changed

cpp11test/src/test-integers.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,20 @@ context("integers-C++") {
207207
}
208208
#endif
209209

210+
test_that("operator[] with names") {
211+
using namespace cpp11::literals;
212+
cpp11::writable::integers x({"a"_nm = 1, "b"_nm = 2});
213+
cpp11::integers y(x);
214+
215+
expect_true(x["a"] == 1);
216+
expect_true(x["b"] == 2);
217+
expect_error(x["c"] == 2);
218+
219+
expect_true(y["a"] == 1);
220+
expect_true(y["b"] == 2);
221+
expect_error(y["c"] == 2);
222+
}
223+
210224
test_that("is_na(integer)") {
211225
int x = 0;
212226
expect_true(!cpp11::is_na(x));

cpp11test/src/test-list.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,28 @@ context("list-C++") {
156156
expect_true(x.size() == nms.size());
157157
}
158158

159+
test_that("list::operator[] by name") {
160+
SEXP x = PROTECT(Rf_allocVector(VECSXP, 1));
161+
162+
SEXP elt = Rf_allocVector(INTSXP, 1);
163+
SET_VECTOR_ELT(x, 0, elt);
164+
SET_INTEGER_ELT(elt, 0, 1);
165+
166+
SEXP names = Rf_allocVector(STRSXP, 1);
167+
Rf_setAttrib(x, R_NamesSymbol, names);
168+
SET_STRING_ELT(names, 0, Rf_mkCharCE("name", CE_UTF8));
169+
170+
cpp11::list lst(x);
171+
172+
expect_true(lst.named());
173+
expect_true(lst["name"] == elt);
174+
175+
// Lists are the only class where OOB accesses by name return `NULL`
176+
expect_true(lst["oob"] == R_NilValue);
177+
178+
UNPROTECT(1);
179+
}
180+
159181
test_that("We don't return NULL for default constructed vectors") {
160182
cpp11::writable::list x;
161183
SEXP y(x);

inst/include/cpp11/list.hpp

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,14 @@ inline typename r_vector<SEXP>::underlying_type r_vector<SEXP>::get_elt(SEXP x,
2727
}
2828

2929
template <>
30-
inline SEXP r_vector<SEXP>::operator[](const r_string& name) const {
31-
SEXP names = this->names();
32-
R_xlen_t size = Rf_xlength(names);
33-
34-
for (R_xlen_t pos = 0; pos < size; ++pos) {
35-
auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos));
36-
if (name == cur) {
37-
return operator[](pos);
38-
}
39-
}
40-
return R_NilValue;
30+
inline typename r_vector<SEXP>::underlying_type* r_vector<SEXP>::get_p(bool, SEXP) {
31+
return nullptr;
4132
}
4233

34+
/// Specialization for lists, where `x["oob"]` returns `R_NilValue`, like at the R level
4335
template <>
44-
inline typename r_vector<SEXP>::underlying_type* r_vector<SEXP>::get_p(bool, SEXP) {
45-
return nullptr;
36+
inline SEXP r_vector<SEXP>::get_oob() {
37+
return R_NilValue;
4638
}
4739

4840
template <>

inst/include/cpp11/r_vector.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ class r_vector {
150150
static void get_region(SEXP x, R_xlen_t i, R_xlen_t n, underlying_type* buf);
151151
/// Implemented in specialization
152152
static SEXPTYPE get_sexptype();
153+
/// Implemented in specialization (throws by default, specialization in list type)
154+
static T get_oob();
153155
static SEXP valid_type(SEXP x);
154156

155157
friend class writable::r_vector<T>;
@@ -467,7 +469,7 @@ inline T r_vector<T>::operator[](const r_string& name) const {
467469
}
468470
}
469471

470-
throw std::out_of_range("r_vector");
472+
return get_oob();
471473
}
472474

473475
#ifdef LONG_VECTOR_SUPPORT
@@ -558,6 +560,11 @@ inline r_vector<r_string> r_vector<T>::names() const {
558560
}
559561
}
560562

563+
template <typename T>
564+
inline T r_vector<T>::get_oob() {
565+
throw std::out_of_range("r_vector");
566+
}
567+
561568
class type_error : public std::exception {
562569
public:
563570
type_error(int expected, int actual) : expected_(expected), actual_(actual) {}

0 commit comments

Comments
 (0)