diff --git a/inst/include/cpp11/doubles.hpp b/inst/include/cpp11/doubles.hpp index 44d24bca..824c294c 100644 --- a/inst/include/cpp11/doubles.hpp +++ b/inst/include/cpp11/doubles.hpp @@ -54,6 +54,11 @@ typedef r_vector doubles; namespace writable { +template <> +inline SEXPTYPE r_vector::get_sexptype() { + return REALSXP; +} + template <> inline typename r_vector::proxy& r_vector::proxy::operator=( const double& rhs) { @@ -104,18 +109,6 @@ inline r_vector::r_vector(std::initializer_list il) } } -template <> -inline void r_vector::reserve(R_xlen_t new_capacity) { - data_ = data_ == R_NilValue ? safe[Rf_allocVector](REALSXP, new_capacity) - : safe[Rf_xlengthgets](data_, new_capacity); - SEXP old_protect = protect_; - protect_ = detail::store::insert(data_); - detail::store::release(old_protect); - - data_p_ = REAL(data_); - capacity_ = new_capacity; -} - template <> inline void r_vector::push_back(double value) { while (length_ >= capacity_) { diff --git a/inst/include/cpp11/integers.hpp b/inst/include/cpp11/integers.hpp index 97f2c6a7..6e7ac8d7 100644 --- a/inst/include/cpp11/integers.hpp +++ b/inst/include/cpp11/integers.hpp @@ -55,6 +55,11 @@ typedef r_vector integers; namespace writable { +template <> +inline SEXPTYPE r_vector::get_sexptype() { + return INTSXP; +} + template <> inline typename r_vector::proxy& r_vector::proxy::operator=(const int& rhs) { if (is_altrep_) { @@ -80,22 +85,6 @@ template <> inline r_vector::r_vector(std::initializer_list il) : cpp11::r_vector(as_sexp(il)), capacity_(il.size()) {} -template <> -inline void r_vector::reserve(R_xlen_t new_capacity) { - data_ = data_ == R_NilValue ? safe[Rf_allocVector](INTSXP, new_capacity) - : safe[Rf_xlengthgets](data_, new_capacity); - SEXP old_protect = protect_; - - // Protect the new data - protect_ = detail::store::insert(data_); - - // Release the old protection; - detail::store::release(old_protect); - - data_p_ = INTEGER(data_); - capacity_ = new_capacity; -} - template <> inline r_vector::r_vector(std::initializer_list il) : cpp11::r_vector(safe[Rf_allocVector](INTSXP, il.size())), diff --git a/inst/include/cpp11/list.hpp b/inst/include/cpp11/list.hpp index 3f258a65..2ee745e6 100644 --- a/inst/include/cpp11/list.hpp +++ b/inst/include/cpp11/list.hpp @@ -63,6 +63,11 @@ typedef r_vector list; namespace writable { +template <> +inline SEXPTYPE r_vector::get_sexptype() { + return VECSXP; +} + template <> inline typename r_vector::proxy& r_vector::proxy::operator=(const SEXP& rhs) { SET_VECTOR_ELT(data_, index_, rhs); @@ -108,18 +113,6 @@ inline r_vector::r_vector(std::initializer_list il) } } -template <> -inline void r_vector::reserve(R_xlen_t new_capacity) { - data_ = data_ == R_NilValue ? safe[Rf_allocVector](VECSXP, new_capacity) - : safe[Rf_xlengthgets](data_, new_capacity); - - SEXP old_protect = protect_; - protect_ = detail::store::insert(data_); - detail::store::release(old_protect); - - capacity_ = new_capacity; -} - template <> inline void r_vector::push_back(SEXP value) { while (length_ >= capacity_) { diff --git a/inst/include/cpp11/logicals.hpp b/inst/include/cpp11/logicals.hpp index 076135a5..7fe94bf5 100644 --- a/inst/include/cpp11/logicals.hpp +++ b/inst/include/cpp11/logicals.hpp @@ -53,6 +53,11 @@ typedef r_vector logicals; namespace writable { +template <> +inline SEXPTYPE r_vector::get_sexptype() { + return LGLSXP; +} + template <> inline typename r_vector::proxy& r_vector::proxy::operator=( const r_bool& rhs) { @@ -110,19 +115,6 @@ inline r_vector::r_vector(std::initializer_list il) } } -template <> -inline void r_vector::reserve(R_xlen_t new_capacity) { - data_ = data_ == R_NilValue ? safe[Rf_allocVector](LGLSXP, new_capacity) - : safe[Rf_xlengthgets](data_, new_capacity); - SEXP old_protect = protect_; - protect_ = detail::store::insert(data_); - - detail::store::release(old_protect); - - data_p_ = LOGICAL(data_); - capacity_ = new_capacity; -} - template <> inline void r_vector::push_back(r_bool value) { while (length_ >= capacity_) { diff --git a/inst/include/cpp11/r_vector.hpp b/inst/include/cpp11/r_vector.hpp index 198a769b..c4b22ee4 100644 --- a/inst/include/cpp11/r_vector.hpp +++ b/inst/include/cpp11/r_vector.hpp @@ -228,8 +228,6 @@ class r_vector : public cpp11::r_vector { void pop_back(); void resize(R_xlen_t count); - - /// Implemented in specialization void reserve(R_xlen_t new_capacity); iterator insert(R_xlen_t pos, T value); @@ -308,6 +306,9 @@ class r_vector : public cpp11::r_vector { }; private: + /// Implemented in specialization + static SEXPTYPE get_sexptype(); + using cpp11::r_vector::get_p; }; } // namespace writable @@ -886,6 +887,26 @@ inline void r_vector::resize(R_xlen_t count) { length_ = count; } +/// Reserve a new capacity and copy all elements over +/// +/// SAFETY: The new capacity is allowed to be smaller than the current capacity, which +/// is used in the `SEXP` conversion operator during truncation, but if that occurs then +/// we also need to update the `length_`, so if you need to truncate then you should call +/// `resize()` instead. +template +inline void r_vector::reserve(R_xlen_t new_capacity) { + SEXP old_protect = protect_; + + data_ = (data_ == R_NilValue) ? safe[Rf_allocVector](get_sexptype(), new_capacity) + : safe[Rf_xlengthgets](data_, new_capacity); + protect_ = detail::store::insert(data_); + is_altrep_ = ALTREP(data_); + data_p_ = get_p(is_altrep_, data_); + capacity_ = new_capacity; + + detail::store::release(old_protect); +} + template inline typename r_vector::iterator r_vector::insert(R_xlen_t pos, T value) { push_back(value); diff --git a/inst/include/cpp11/raws.hpp b/inst/include/cpp11/raws.hpp index 419ce63f..531b6d0f 100644 --- a/inst/include/cpp11/raws.hpp +++ b/inst/include/cpp11/raws.hpp @@ -62,6 +62,11 @@ typedef r_vector raws; namespace writable { +template <> +inline SEXPTYPE r_vector::get_sexptype() { + return RAWSXP; +} + template <> inline typename r_vector::proxy& r_vector::proxy::operator=( const uint8_t& rhs) { @@ -119,19 +124,6 @@ inline r_vector::r_vector(std::initializer_list il) } } -template <> -inline void r_vector::reserve(R_xlen_t new_capacity) { - data_ = data_ == R_NilValue ? safe[Rf_allocVector](RAWSXP, new_capacity) - : safe[Rf_xlengthgets](data_, new_capacity); - - SEXP old_protect = protect_; - protect_ = detail::store::insert(data_); - detail::store::release(old_protect); - - data_p_ = RAW(data_); - capacity_ = new_capacity; -} - template <> inline void r_vector::push_back(uint8_t value) { while (length_ >= capacity_) { diff --git a/inst/include/cpp11/strings.hpp b/inst/include/cpp11/strings.hpp index 2e1390e0..c121b039 100644 --- a/inst/include/cpp11/strings.hpp +++ b/inst/include/cpp11/strings.hpp @@ -53,6 +53,11 @@ typedef r_vector strings; namespace writable { +template <> +inline SEXPTYPE r_vector::get_sexptype() { + return STRSXP; +} + template <> inline typename r_vector::proxy& r_vector::proxy::operator=( const r_string& rhs) { @@ -136,18 +141,6 @@ inline r_vector::r_vector(std::initializer_list il) } } -template <> -inline void r_vector::reserve(R_xlen_t new_capacity) { - data_ = data_ == R_NilValue ? safe[Rf_allocVector](STRSXP, new_capacity) - : safe[Rf_xlengthgets](data_, new_capacity); - - SEXP old_protect = protect_; - protect_ = detail::store::insert(data_); - detail::store::release(old_protect); - - capacity_ = new_capacity; -} - template <> inline void r_vector::push_back(r_string value) { while (length_ >= capacity_) {