Skip to content

Commit

Permalink
Add get_elt() to unify more specialization methods (#380)
Browse files Browse the repository at this point in the history
* Add `get_elt()` helper

* Move `[]` element access operator to `r_vector.hpp`

* Implement `proxy::operator T()` in `r_vector.hpp`
  • Loading branch information
DavisVaughan authored Aug 9, 2024
1 parent dccd4f6 commit 364e713
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 87 deletions.
23 changes: 7 additions & 16 deletions inst/include/cpp11/doubles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@

namespace cpp11 {

template <>
inline typename r_vector<double>::underlying_type r_vector<double>::get_elt(SEXP x,
R_xlen_t i) {
// NOPROTECT: likely too costly to unwind protect every elt
return REAL_ELT(x, i);
}

template <>
inline SEXP r_vector<double>::valid_type(SEXP data) {
if (data == nullptr) {
Expand All @@ -27,12 +34,6 @@ inline SEXP r_vector<double>::valid_type(SEXP data) {
return data;
}

template <>
inline double r_vector<double>::operator[](const R_xlen_t pos) const {
// NOPROTECT: likely too costly to unwind protect every elt
return is_altrep_ ? REAL_ELT(data_, pos) : data_p_[pos];
}

template <>
inline typename r_vector<double>::underlying_type* r_vector<double>::get_p(bool is_altrep,
SEXP data) {
Expand Down Expand Up @@ -70,16 +71,6 @@ inline void r_vector<double>::set_elt(SEXP x, R_xlen_t i,
SET_REAL_ELT(x, i, value);
}

template <>
inline r_vector<double>::proxy::operator double() const {
if (p_ == nullptr) {
// NOPROTECT: likely too costly to unwind protect every elt
return REAL_ELT(data_, index_);
} else {
return *p_;
}
}

template <>
inline r_vector<double>::r_vector(std::initializer_list<named_arg> il)
: cpp11::r_vector<double>(safe[Rf_allocVector](REALSXP, il.size())),
Expand Down
23 changes: 7 additions & 16 deletions inst/include/cpp11/integers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@

namespace cpp11 {

template <>
inline typename r_vector<int>::underlying_type r_vector<int>::get_elt(SEXP x,
R_xlen_t i) {
// NOPROTECT: likely too costly to unwind protect every elt
return INTEGER_ELT(x, i);
}

template <>
inline SEXP r_vector<int>::valid_type(SEXP data) {
if (data == nullptr) {
Expand All @@ -28,12 +35,6 @@ inline SEXP r_vector<int>::valid_type(SEXP data) {
return data;
}

template <>
inline int r_vector<int>::operator[](const R_xlen_t pos) const {
// NOPROTECT: likely too costly to unwind protect every elt
return is_altrep_ ? INTEGER_ELT(data_, pos) : data_p_[pos];
}

template <>
inline typename r_vector<int>::underlying_type* r_vector<int>::get_p(bool is_altrep,
SEXP data) {
Expand Down Expand Up @@ -71,16 +72,6 @@ inline void r_vector<int>::set_elt(SEXP x, R_xlen_t i,
SET_INTEGER_ELT(x, i, value);
}

template <>
inline r_vector<int>::proxy::operator int() const {
if (p_ == nullptr) {
// NOPROTECT: likely too costly to unwind protect every elt
return INTEGER_ELT(data_, index_);
} else {
return *p_;
}
}

template <>
inline r_vector<int>::r_vector(std::initializer_list<named_arg> il)
: cpp11::r_vector<int>(safe[Rf_allocVector](INTSXP, il.size())),
Expand Down
17 changes: 7 additions & 10 deletions inst/include/cpp11/list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@

namespace cpp11 {

template <>
inline typename r_vector<SEXP>::underlying_type r_vector<SEXP>::get_elt(SEXP x,
R_xlen_t i) {
// NOPROTECT: likely too costly to unwind protect every elt
return VECTOR_ELT(x, i);
}

template <>
inline SEXP r_vector<SEXP>::valid_type(SEXP data) {
if (data == nullptr) {
Expand All @@ -25,11 +32,6 @@ inline SEXP r_vector<SEXP>::valid_type(SEXP data) {
return data;
}

template <>
inline SEXP r_vector<SEXP>::operator[](const R_xlen_t pos) const {
return VECTOR_ELT(data_, pos);
}

template <>
inline SEXP r_vector<SEXP>::operator[](const r_string& name) const {
SEXP names = this->names();
Expand Down Expand Up @@ -80,11 +82,6 @@ inline void r_vector<SEXP>::set_elt(SEXP x, R_xlen_t i,
SET_VECTOR_ELT(x, i, value);
}

template <>
inline r_vector<SEXP>::proxy::operator SEXP() const {
return VECTOR_ELT(data_, index_);
}

template <>
inline r_vector<SEXP>::r_vector(std::initializer_list<named_arg> il)
: cpp11::r_vector<SEXP>(safe[Rf_allocVector](VECSXP, il.size())),
Expand Down
21 changes: 7 additions & 14 deletions inst/include/cpp11/logicals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@

namespace cpp11 {

template <>
inline typename r_vector<r_bool>::underlying_type r_vector<r_bool>::get_elt(SEXP x,
R_xlen_t i) {
// NOPROTECT: likely too costly to unwind protect every elt
return LOGICAL_ELT(x, i);
}

template <>
inline SEXP r_vector<r_bool>::valid_type(SEXP data) {
if (data == nullptr) {
Expand All @@ -27,11 +34,6 @@ inline SEXP r_vector<r_bool>::valid_type(SEXP data) {
return data;
}

template <>
inline r_bool r_vector<r_bool>::operator[](const R_xlen_t pos) const {
return is_altrep_ ? LOGICAL_ELT(data_, pos) : data_p_[pos];
}

template <>
inline typename r_vector<r_bool>::underlying_type* r_vector<r_bool>::get_p(bool is_altrep,
SEXP data) {
Expand Down Expand Up @@ -80,15 +82,6 @@ inline typename r_vector<r_bool>::proxy& r_vector<r_bool>::proxy::operator=(
return *this;
}

template <>
inline r_vector<r_bool>::proxy::operator r_bool() const {
if (p_ == nullptr) {
return LOGICAL_ELT(data_, index_);
} else {
return *p_;
}
}

inline bool operator==(const r_vector<r_bool>::proxy& lhs, r_bool rhs) {
return static_cast<r_bool>(lhs).operator==(rhs);
}
Expand Down
19 changes: 16 additions & 3 deletions inst/include/cpp11/r_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ class r_vector {
#ifdef LONG_VECTOR_SUPPORT
T operator[](const int pos) const;
#endif
/// Implemented by specialization
T operator[](const R_xlen_t pos) const;
T operator[](const size_type pos) const;
T operator[](const r_string& name) const;
Expand Down Expand Up @@ -143,6 +142,8 @@ class r_vector {
};

private:
/// Implemented in specialization
static underlying_type get_elt(SEXP x, R_xlen_t i);
/// Implemented in specialization
static underlying_type* get_p(bool is_altrep, SEXP data);
/// Implemented in specialization
Expand Down Expand Up @@ -262,7 +263,6 @@ class r_vector : public cpp11::r_vector<T> {
public:
proxy(SEXP data, const R_xlen_t index, underlying_type* const p, bool is_altrep);

/// Implemented in specialization
proxy& operator=(const T& rhs);
proxy& operator+=(const T& rhs);
proxy& operator-=(const T& rhs);
Expand All @@ -274,7 +274,6 @@ class r_vector : public cpp11::r_vector<T> {
void operator++();
void operator--();

/// Implemented in specialization
operator T() const;
};

Expand Down Expand Up @@ -445,6 +444,13 @@ inline T r_vector<T>::operator[](const int pos) const {
}
#endif

template <typename T>
inline T r_vector<T>::operator[](const R_xlen_t pos) const {
// Handles ALTREP, VECSXP, and STRSXP cases through `get_elt()`
const underlying_type elt = (data_p_ != nullptr) ? data_p_[pos] : get_elt(data_, pos);
return static_cast<T>(elt);
}

template <typename T>
inline T r_vector<T>::operator[](const size_type pos) const {
return operator[](static_cast<R_xlen_t>(pos));
Expand Down Expand Up @@ -1082,6 +1088,13 @@ inline void r_vector<T>::proxy::operator--() {
operator=(static_cast<T>(*this) - 1);
}

template <typename T>
inline r_vector<T>::proxy::operator T() const {
// Handles ALTREP, VECSXP, and STRSXP cases through `get_elt()`
const underlying_type elt = (p_ != nullptr) ? *p_ : r_vector::get_elt(data_, index_);
return static_cast<T>(elt);
}

template <typename T>
r_vector<T>::iterator::iterator(const r_vector& data, R_xlen_t pos)
: r_vector::const_iterator(&data, pos), data_(data) {}
Expand Down
23 changes: 7 additions & 16 deletions inst/include/cpp11/raws.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ struct get_underlying_type<uint8_t> {
};
} // namespace traits

template <>
inline typename r_vector<uint8_t>::underlying_type r_vector<uint8_t>::get_elt(
SEXP x, R_xlen_t i) {
// NOPROTECT: likely too costly to unwind protect every elt
return RAW_ELT(x, i);
}

template <>
inline SEXP r_vector<uint8_t>::valid_type(SEXP data) {
if (data == nullptr) {
Expand All @@ -35,12 +42,6 @@ inline SEXP r_vector<uint8_t>::valid_type(SEXP data) {
return data;
}

template <>
inline uint8_t r_vector<uint8_t>::operator[](const R_xlen_t pos) const {
// NOPROTECT: likely too costly to unwind protect every elt
return is_altrep_ ? RAW_ELT(data_, pos) : data_p_[pos];
}

template <>
inline typename r_vector<uint8_t>::underlying_type* r_vector<uint8_t>::get_p(
bool is_altrep, SEXP data) {
Expand Down Expand Up @@ -82,16 +83,6 @@ inline void r_vector<uint8_t>::set_elt(SEXP x, R_xlen_t i,
#endif
}

template <>
inline r_vector<uint8_t>::proxy::operator uint8_t() const {
if (p_ == nullptr) {
// NOPROTECT: likely too costly to unwind protect every elt
return RAW(data_)[index_];
} else {
return *p_;
}
}

template <>
inline r_vector<uint8_t>::r_vector(std::initializer_list<named_arg> il)
: cpp11::r_vector<uint8_t>(safe[Rf_allocVector](RAWSXP, il.size())),
Expand Down
19 changes: 7 additions & 12 deletions inst/include/cpp11/strings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@

namespace cpp11 {

template <>
inline typename r_vector<r_string>::underlying_type r_vector<r_string>::get_elt(
SEXP x, R_xlen_t i) {
// NOPROTECT: likely too costly to unwind protect every elt
return STRING_ELT(x, i);
}

template <>
inline SEXP r_vector<r_string>::valid_type(SEXP data) {
if (data == nullptr) {
Expand All @@ -27,12 +34,6 @@ inline SEXP r_vector<r_string>::valid_type(SEXP data) {
return data;
}

template <>
inline r_string r_vector<r_string>::operator[](const R_xlen_t pos) const {
// NOPROTECT: likely too costly to unwind protect every elt
return STRING_ELT(data_, pos);
}

template <>
inline typename r_vector<r_string>::underlying_type* r_vector<r_string>::get_p(bool,
SEXP) {
Expand Down Expand Up @@ -70,12 +71,6 @@ inline void r_vector<r_string>::set_elt(SEXP x, R_xlen_t i,
SET_STRING_ELT(x, i, value);
}

template <>
inline r_vector<r_string>::proxy::operator r_string() const {
// NOPROTECT: likely too costly to unwind protect every elt
return STRING_ELT(data_, index_);
}

inline bool operator==(const r_vector<r_string>::proxy& lhs, r_string rhs) {
return static_cast<r_string>(lhs).operator==(static_cast<std::string>(rhs).c_str());
}
Expand Down

0 comments on commit 364e713

Please sign in to comment.