Skip to content

Commit

Permalink
Unify valid_type() implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
DavisVaughan committed Aug 9, 2024
1 parent 364e713 commit 888afdb
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 115 deletions.
21 changes: 5 additions & 16 deletions inst/include/cpp11/doubles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,18 @@

namespace cpp11 {

template <>
inline SEXPTYPE r_vector<double>::get_sexptype() {
return REALSXP;
}

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) {
throw type_error(REALSXP, NILSXP);
}
if (TYPEOF(data) != REALSXP) {
throw type_error(REALSXP, TYPEOF(data));
}
return data;
}

template <>
inline typename r_vector<double>::underlying_type* r_vector<double>::get_p(bool is_altrep,
SEXP data) {
Expand All @@ -60,11 +54,6 @@ typedef r_vector<double> doubles;

namespace writable {

template <>
inline SEXPTYPE r_vector<double>::get_sexptype() {
return REALSXP;
}

template <>
inline void r_vector<double>::set_elt(SEXP x, R_xlen_t i,
typename r_vector::underlying_type value) {
Expand Down
21 changes: 5 additions & 16 deletions inst/include/cpp11/integers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,18 @@

namespace cpp11 {

template <>
inline SEXPTYPE r_vector<int>::get_sexptype() {
return INTSXP;
}

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) {
throw type_error(INTSXP, NILSXP);
}
if (TYPEOF(data) != INTSXP) {
throw type_error(INTSXP, TYPEOF(data));
}
return data;
}

template <>
inline typename r_vector<int>::underlying_type* r_vector<int>::get_p(bool is_altrep,
SEXP data) {
Expand All @@ -61,11 +55,6 @@ typedef r_vector<int> integers;

namespace writable {

template <>
inline SEXPTYPE r_vector<int>::get_sexptype() {
return INTSXP;
}

template <>
inline void r_vector<int>::set_elt(SEXP x, R_xlen_t i,
typename r_vector::underlying_type value) {
Expand Down
21 changes: 5 additions & 16 deletions inst/include/cpp11/list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,18 @@

namespace cpp11 {

template <>
inline SEXPTYPE r_vector<SEXP>::get_sexptype() {
return VECSXP;
}

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) {
throw type_error(VECSXP, NILSXP);
}
if (TYPEOF(data) != VECSXP) {
throw type_error(VECSXP, TYPEOF(data));
}
return data;
}

template <>
inline SEXP r_vector<SEXP>::operator[](const r_string& name) const {
SEXP names = this->names();
Expand Down Expand Up @@ -71,11 +65,6 @@ typedef r_vector<SEXP> list;

namespace writable {

template <>
inline SEXPTYPE r_vector<SEXP>::get_sexptype() {
return VECSXP;
}

template <>
inline void r_vector<SEXP>::set_elt(SEXP x, R_xlen_t i,
typename r_vector::underlying_type value) {
Expand Down
21 changes: 5 additions & 16 deletions inst/include/cpp11/logicals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,18 @@

namespace cpp11 {

template <>
inline SEXPTYPE r_vector<r_bool>::get_sexptype() {
return LGLSXP;
}

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) {
throw type_error(LGLSXP, NILSXP);
}
if (TYPEOF(data) != LGLSXP) {
throw type_error(LGLSXP, TYPEOF(data));
}
return data;
}

template <>
inline typename r_vector<r_bool>::underlying_type* r_vector<r_bool>::get_p(bool is_altrep,
SEXP data) {
Expand All @@ -60,11 +54,6 @@ typedef r_vector<r_bool> logicals;

namespace writable {

template <>
inline SEXPTYPE r_vector<r_bool>::get_sexptype() {
return LGLSXP;
}

template <>
inline void r_vector<r_bool>::set_elt(SEXP x, R_xlen_t i,
typename r_vector::underlying_type value) {
Expand Down
51 changes: 32 additions & 19 deletions inst/include/cpp11/r_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ class r_vector {
/// Implemented in specialization
static void get_region(SEXP x, R_xlen_t i, R_xlen_t n, underlying_type* buf);
/// Implemented in specialization
static SEXP valid_type(SEXP data);
static SEXPTYPE get_sexptype();
static SEXP valid_type(SEXP x);

friend class writable::r_vector<T>;
};
Expand Down Expand Up @@ -308,12 +309,11 @@ class r_vector : public cpp11::r_vector<T> {
};

private:
/// Implemented in specialization
static SEXPTYPE get_sexptype();
/// Implemented in specialization
static void set_elt(SEXP x, R_xlen_t i, underlying_type value);

using cpp11::r_vector<T>::get_p;
using cpp11::r_vector<T>::get_sexptype;
};
} // namespace writable

Expand Down Expand Up @@ -559,6 +559,35 @@ inline r_vector<r_string> r_vector<T>::names() const {
}
}

class type_error : public std::exception {
public:
type_error(int expected, int actual) : expected_(expected), actual_(actual) {}
virtual const char* what() const noexcept override {
snprintf(str_, 64, "Invalid input type, expected '%s' actual '%s'",
Rf_type2char(expected_), Rf_type2char(actual_));
return str_;
}

private:
int expected_;
int actual_;
mutable char str_[64];
};

template <typename T>
inline SEXP r_vector<T>::valid_type(SEXP x) {
const SEXPTYPE type = get_sexptype();

if (x == nullptr) {
throw type_error(type, NILSXP);
}
if (TYPEOF(x) != type) {
throw type_error(type, TYPEOF(x));
}

return x;
}

template <typename T>
inline typename r_vector<T>::const_iterator r_vector<T>::begin() const {
return const_iterator(this, 0);
Expand Down Expand Up @@ -1200,20 +1229,4 @@ bool operator!=(const r_vector<T>& lhs, const r_vector<T>& rhs) {
return !(lhs == rhs);
}

// Special helper class used by specializations to throw consistent exceptions
class type_error : public std::exception {
public:
type_error(int expected, int actual) : expected_(expected), actual_(actual) {}
virtual const char* what() const noexcept override {
snprintf(str_, 64, "Invalid input type, expected '%s' actual '%s'",
Rf_type2char(expected_), Rf_type2char(actual_));
return str_;
}

private:
int expected_;
int actual_;
mutable char str_[64];
};

} // namespace cpp11
21 changes: 5 additions & 16 deletions inst/include/cpp11/raws.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,18 @@ struct get_underlying_type<uint8_t> {
};
} // namespace traits

template <>
inline SEXPTYPE r_vector<uint8_t>::get_sexptype() {
return RAWSXP;
}

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) {
throw type_error(RAWSXP, NILSXP);
}
if (TYPEOF(data) != RAWSXP) {
throw type_error(RAWSXP, TYPEOF(data));
}
return data;
}

template <>
inline typename r_vector<uint8_t>::underlying_type* r_vector<uint8_t>::get_p(
bool is_altrep, SEXP data) {
Expand All @@ -68,11 +62,6 @@ typedef r_vector<uint8_t> raws;

namespace writable {

template <>
inline SEXPTYPE r_vector<uint8_t>::get_sexptype() {
return RAWSXP;
}

template <>
inline void r_vector<uint8_t>::set_elt(SEXP x, R_xlen_t i,
typename r_vector::underlying_type value) {
Expand Down
21 changes: 5 additions & 16 deletions inst/include/cpp11/strings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,18 @@

namespace cpp11 {

template <>
inline SEXPTYPE r_vector<r_string>::get_sexptype() {
return STRSXP;
}

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) {
throw type_error(STRSXP, NILSXP);
}
if (TYPEOF(data) != STRSXP) {
throw type_error(STRSXP, TYPEOF(data));
}
return data;
}

template <>
inline typename r_vector<r_string>::underlying_type* r_vector<r_string>::get_p(bool,
SEXP) {
Expand All @@ -60,11 +54,6 @@ typedef r_vector<r_string> strings;

namespace writable {

template <>
inline SEXPTYPE r_vector<r_string>::get_sexptype() {
return STRSXP;
}

template <>
inline void r_vector<r_string>::set_elt(SEXP x, R_xlen_t i,
typename r_vector::underlying_type value) {
Expand Down

0 comments on commit 888afdb

Please sign in to comment.