diff --git a/inst/include/cpp11/doubles.hpp b/inst/include/cpp11/doubles.hpp index f15cbf07..45e3c89f 100644 --- a/inst/include/cpp11/doubles.hpp +++ b/inst/include/cpp11/doubles.hpp @@ -44,10 +44,16 @@ inline typename r_vector::underlying_type* r_vector::get_p(bool } template <> -inline void r_vector::const_iterator::fill_buf(R_xlen_t pos) { - length_ = std::min(64_xl, data_->size() - pos); - REAL_GET_REGION(data_->data_, pos, length_, buf_.data()); - block_start_ = pos; +inline void r_vector::get_region( + SEXP x, R_xlen_t i, R_xlen_t n, + typename traits::get_underlying_type::type* buf) { + // NOPROTECT: likely too costly to unwind protect here + REAL_GET_REGION(x, i, n, buf); +}; + +template <> +inline bool r_vector::const_iterator::use_buf(bool is_altrep) { + return is_altrep; } typedef r_vector doubles; diff --git a/inst/include/cpp11/integers.hpp b/inst/include/cpp11/integers.hpp index 3bf25203..fba42669 100644 --- a/inst/include/cpp11/integers.hpp +++ b/inst/include/cpp11/integers.hpp @@ -45,10 +45,16 @@ inline typename r_vector::underlying_type* r_vector::get_p(bool is_alt } template <> -inline void r_vector::const_iterator::fill_buf(R_xlen_t pos) { - length_ = std::min(64_xl, data_->size() - pos); - INTEGER_GET_REGION(data_->data_, pos, length_, buf_.data()); - block_start_ = pos; +inline void r_vector::get_region( + SEXP x, R_xlen_t i, R_xlen_t n, + typename traits::get_underlying_type::type* buf) { + // NOPROTECT: likely too costly to unwind protect here + INTEGER_GET_REGION(x, i, n, buf); +}; + +template <> +inline bool r_vector::const_iterator::use_buf(bool is_altrep) { + return is_altrep; } typedef r_vector integers; diff --git a/inst/include/cpp11/list.hpp b/inst/include/cpp11/list.hpp index 89c837a5..1f9d09d4 100644 --- a/inst/include/cpp11/list.hpp +++ b/inst/include/cpp11/list.hpp @@ -50,8 +50,15 @@ inline typename r_vector::underlying_type* r_vector::get_p(bool, SEX } template <> -inline void r_vector::const_iterator::fill_buf(R_xlen_t) { - return; +inline void r_vector::get_region( + SEXP x, R_xlen_t i, R_xlen_t n, + typename traits::get_underlying_type::type* buf) { + cpp11::stop("Unreachable!"); +}; + +template <> +inline bool r_vector::const_iterator::use_buf(bool is_altrep) { + return false; } template <> diff --git a/inst/include/cpp11/logicals.hpp b/inst/include/cpp11/logicals.hpp index 99f5204c..ec392583 100644 --- a/inst/include/cpp11/logicals.hpp +++ b/inst/include/cpp11/logicals.hpp @@ -43,10 +43,16 @@ inline typename r_vector::underlying_type* r_vector::get_p(bool } template <> -inline void r_vector::const_iterator::fill_buf(R_xlen_t pos) { - length_ = std::min(64_xl, data_->size() - pos); - LOGICAL_GET_REGION(data_->data_, pos, length_, buf_.data()); - block_start_ = pos; +inline void r_vector::get_region( + SEXP x, R_xlen_t i, R_xlen_t n, + typename traits::get_underlying_type::type* buf) { + // NOPROTECT: likely too costly to unwind protect here + LOGICAL_GET_REGION(x, i, n, buf); +}; + +template <> +inline bool r_vector::const_iterator::use_buf(bool is_altrep) { + return is_altrep; } typedef r_vector logicals; diff --git a/inst/include/cpp11/r_vector.hpp b/inst/include/cpp11/r_vector.hpp index 44cca1e6..ea6bf4b3 100644 --- a/inst/include/cpp11/r_vector.hpp +++ b/inst/include/cpp11/r_vector.hpp @@ -138,6 +138,7 @@ class r_vector { private: /// Implemented in specialization + static bool use_buf(bool is_altrep); void fill_buf(R_xlen_t pos); }; @@ -145,6 +146,8 @@ class r_vector { /// Implemented in specialization static underlying_type* get_p(bool is_altrep, SEXP data); /// 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); friend class writable::r_vector; @@ -283,6 +286,7 @@ class r_vector : public cpp11::r_vector { using cpp11::r_vector::const_iterator::pos_; using cpp11::r_vector::const_iterator::buf_; using cpp11::r_vector::const_iterator::length_; + using cpp11::r_vector::const_iterator::use_buf; using cpp11::r_vector::const_iterator::fill_buf; public: @@ -572,7 +576,7 @@ inline typename r_vector::const_iterator r_vector::cend() const { template r_vector::const_iterator::const_iterator(const r_vector* data, R_xlen_t pos) : data_(data), pos_(pos), buf_() { - if (data_->is_altrep()) { + if (use_buf(data_->is_altrep())) { fill_buf(pos); } } @@ -580,7 +584,7 @@ r_vector::const_iterator::const_iterator(const r_vector* data, R_xlen_t pos) template inline typename r_vector::const_iterator& r_vector::const_iterator::operator++() { ++pos_; - if (data_->is_altrep() && pos_ >= block_start_ + length_) { + if (use_buf(data_->is_altrep()) && pos_ >= block_start_ + length_) { fill_buf(pos_); } return *this; @@ -589,7 +593,7 @@ inline typename r_vector::const_iterator& r_vector::const_iterator::operat template inline typename r_vector::const_iterator& r_vector::const_iterator::operator--() { --pos_; - if (data_->is_altrep() && pos_ > 0 && pos_ < block_start_) { + if (use_buf(data_->is_altrep()) && pos_ > 0 && pos_ < block_start_) { fill_buf(std::max(0_xl, pos_ - 64)); } return *this; @@ -599,7 +603,7 @@ template inline typename r_vector::const_iterator& r_vector::const_iterator::operator+=( R_xlen_t i) { pos_ += i; - if (data_->is_altrep() && pos_ >= block_start_ + length_) { + if (use_buf(data_->is_altrep()) && pos_ >= block_start_ + length_) { fill_buf(pos_); } return *this; @@ -609,7 +613,7 @@ template inline typename r_vector::const_iterator& r_vector::const_iterator::operator-=( R_xlen_t i) { pos_ -= i; - if (data_->is_altrep() && pos_ >= block_start_ + length_) { + if (use_buf(data_->is_altrep()) && pos_ >= block_start_ + length_) { fill_buf(std::max(0_xl, pos_ - 64)); } return *this; @@ -666,6 +670,14 @@ inline T r_vector::const_iterator::operator*() const { } } +template +inline void r_vector::const_iterator::fill_buf(R_xlen_t pos) { + using namespace cpp11::literals; + length_ = std::min(64_xl, data_->size() - pos); + get_region(data_->data_, pos, length_, buf_.data()); + block_start_ = pos; +} + namespace writable { template @@ -1062,7 +1074,7 @@ r_vector::iterator::iterator(const r_vector& data, R_xlen_t pos) template inline typename r_vector::iterator& r_vector::iterator::operator++() { ++pos_; - if (data_.is_altrep() && pos_ >= block_start_ + length_) { + if (use_buf(data_.is_altrep()) && pos_ >= block_start_ + length_) { fill_buf(pos_); } return *this; @@ -1070,7 +1082,7 @@ inline typename r_vector::iterator& r_vector::iterator::operator++() { template inline typename r_vector::proxy r_vector::iterator::operator*() const { - if (data_.is_altrep()) { + if (use_buf(data_.is_altrep())) { return proxy( data_.data(), pos_, const_cast(&buf_[pos_ - block_start_]), @@ -1084,7 +1096,7 @@ inline typename r_vector::proxy r_vector::iterator::operator*() const { template inline typename r_vector::iterator& r_vector::iterator::operator+=(R_xlen_t rhs) { pos_ += rhs; - if (data_.is_altrep() && pos_ >= block_start_ + length_) { + if (use_buf(data_.is_altrep()) && pos_ >= block_start_ + length_) { fill_buf(pos_); } return *this; diff --git a/inst/include/cpp11/raws.hpp b/inst/include/cpp11/raws.hpp index c6705bcb..9f198066 100644 --- a/inst/include/cpp11/raws.hpp +++ b/inst/include/cpp11/raws.hpp @@ -52,11 +52,16 @@ inline typename r_vector::underlying_type* r_vector::get_p( } template <> -inline void r_vector::const_iterator::fill_buf(R_xlen_t pos) { - using namespace cpp11::literals; - length_ = std::min(64_xl, data_->size() - pos); - unwind_protect([&] { RAW_GET_REGION(data_->data_, pos, length_, buf_.data()); }); - block_start_ = pos; +inline void r_vector::get_region( + SEXP x, R_xlen_t i, R_xlen_t n, + typename traits::get_underlying_type::type* buf) { + // NOPROTECT: likely too costly to unwind protect here + RAW_GET_REGION(x, i, n, buf); +}; + +template <> +inline bool r_vector::const_iterator::use_buf(bool is_altrep) { + return is_altrep; } typedef r_vector raws; diff --git a/inst/include/cpp11/strings.hpp b/inst/include/cpp11/strings.hpp index 64cee045..d7dcd0a2 100644 --- a/inst/include/cpp11/strings.hpp +++ b/inst/include/cpp11/strings.hpp @@ -40,8 +40,15 @@ inline typename r_vector::underlying_type* r_vector::get_p(b } template <> -inline void r_vector::const_iterator::fill_buf(R_xlen_t) { - return; +inline void r_vector::get_region( + SEXP x, R_xlen_t i, R_xlen_t n, + typename traits::get_underlying_type::type* buf) { + cpp11::stop("Unreachable!"); +}; + +template <> +inline bool r_vector::const_iterator::use_buf(bool is_altrep) { + return false; } template <>