// cpp11 version: 0.3.1.1 // vendored on: 2021-08-11 #pragma once #include // for initializer_list #include // for string, basic_string #include "cpp11/R.hpp" // for SEXP, TYPEOF, SEXPREC, SET_STRI... #include "cpp11/as.hpp" // for as_sexp #include "cpp11/attribute_proxy.hpp" // for attribute_proxy #include "cpp11/named_arg.hpp" // for named_arg #include "cpp11/protect.hpp" // for preserved #include "cpp11/r_string.hpp" // for r_string #include "cpp11/r_vector.hpp" // for r_vector, r_vector<>::proxy #include "cpp11/sexp.hpp" // for sexp // Specializations for strings namespace cpp11 { template <> inline SEXP r_vector::valid_type(SEXP data) { if (TYPEOF(data) != STRSXP) { throw type_error(STRSXP, TYPEOF(data)); } return data; } template <> inline r_string r_vector::operator[](const R_xlen_t pos) const { // NOPROTECT: likely too costly to unwind protect every elt return STRING_ELT(data_, pos); } template <> inline r_string* r_vector::get_p(bool, SEXP) { return nullptr; } template <> inline void r_vector::const_iterator::fill_buf(R_xlen_t) { return; } template <> inline r_string r_vector::const_iterator::operator*() const { return STRING_ELT(data_->data(), pos_); } typedef r_vector strings; namespace writable { template <> inline typename r_vector::proxy& r_vector::proxy::operator=( const r_string& rhs) { unwind_protect([&] { SET_STRING_ELT(data_, index_, rhs); }); return *this; } template <> inline r_vector::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::proxy& lhs, r_string rhs) { return static_cast(lhs).operator==(static_cast(rhs).c_str()); } inline SEXP alloc_or_copy(const SEXP data) { switch (TYPEOF(data)) { case CHARSXP: return cpp11::r_vector(safe[Rf_allocVector](STRSXP, 1)); case STRSXP: return safe[Rf_shallow_duplicate](data); default: throw type_error(STRSXP, TYPEOF(data)); } } inline SEXP alloc_if_charsxp(const SEXP data) { switch (TYPEOF(data)) { case CHARSXP: return cpp11::r_vector(safe[Rf_allocVector](STRSXP, 1)); case STRSXP: return data; default: throw type_error(STRSXP, TYPEOF(data)); } } template <> inline r_vector::r_vector(const SEXP& data) : cpp11::r_vector(alloc_or_copy(data)), protect_(preserved.insert(data_)), capacity_(length_) { if (TYPEOF(data) == CHARSXP) { SET_STRING_ELT(data_, 0, data); } } template <> inline r_vector::r_vector(SEXP&& data) : cpp11::r_vector(alloc_if_charsxp(data)), protect_(preserved.insert(data_)), capacity_(length_) { if (TYPEOF(data) == CHARSXP) { SET_STRING_ELT(data_, 0, data); } } template <> inline r_vector::r_vector(std::initializer_list il) : cpp11::r_vector(as_sexp(il)), capacity_(il.size()) {} template <> inline r_vector::r_vector(std::initializer_list il) : cpp11::r_vector(as_sexp(il)), capacity_(il.size()) {} template <> inline r_vector::r_vector(std::initializer_list il) : cpp11::r_vector(as_sexp(il)), capacity_(il.size()) {} template <> inline r_vector::r_vector(std::initializer_list il) : cpp11::r_vector(safe[Rf_allocVector](STRSXP, il.size())), capacity_(il.size()) { protect_ = preserved.insert(data_); int n_protected = 0; try { unwind_protect([&] { Rf_setAttrib(data_, R_NamesSymbol, Rf_allocVector(STRSXP, capacity_)); SEXP names = PROTECT(Rf_getAttrib(data_, R_NamesSymbol)); ++n_protected; auto it = il.begin(); for (R_xlen_t i = 0; i < capacity_; ++i, ++it) { SET_STRING_ELT(data_, i, STRING_ELT(it->value(), 0)); SET_STRING_ELT(names, i, Rf_mkCharCE(it->name(), CE_UTF8)); } UNPROTECT(n_protected); }); } catch (const unwind_exception& e) { preserved.release(protect_); UNPROTECT(n_protected); throw e; } } 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_ = preserved.insert(data_); preserved.release(old_protect); capacity_ = new_capacity; } template <> inline void r_vector::push_back(r_string value) { while (length_ >= capacity_) { reserve(capacity_ == 0 ? 1 : capacity_ *= 2); } unwind_protect([&] { SET_STRING_ELT(data_, length_, value); }); ++length_; } typedef r_vector strings; template inline void r_vector::push_back(const named_arg& value) { push_back(value.value()); if (Rf_xlength(names()) == 0) { cpp11::writable::strings new_nms(size()); names() = new_nms; } cpp11::writable::strings nms(names()); nms[size() - 1] = value.name(); } } // namespace writable } // namespace cpp11