Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 50 additions & 10 deletions inst/include/cpp11/r_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,9 @@ class r_vector : public cpp11::r_vector<T> {
proxy at(const r_string& name) const;

void push_back(T value);
/// Implemented in `strings.hpp`
template <typename U = T,
typename std::enable_if<std::is_same<U, r_string>::value>::type* = nullptr>
void push_back(const std::string& value); // Pacha: r_string only (#406)
void push_back(const named_arg& value);
void pop_back();

Expand All @@ -256,6 +258,15 @@ class r_vector : public cpp11::r_vector<T> {

iterator find(const r_string& name) const;

/// Get the value at position without returning a proxy
/// This is useful when you need the actual value (e.g., for C-style printf functions)
/// that don't trigger implicit conversions from proxy types
#ifdef LONG_VECTOR_SUPPORT
T value(const int pos) const;
#endif
T value(const R_xlen_t pos) const;
T value(const size_type pos) const;

attribute_proxy<r_vector<T>> attr(const char* name) const;
attribute_proxy<r_vector<T>> attr(const std::string& name) const;
attribute_proxy<r_vector<T>> attr(SEXP name) const;
Expand Down Expand Up @@ -865,7 +876,8 @@ inline r_vector<T>::r_vector(std::initializer_list<named_arg> il)
}

unwind_protect([&] {
SEXP names = Rf_allocVector(STRSXP, capacity_);
SEXP names;
PROTECT(names = Rf_allocVector(STRSXP, capacity_));
Rf_setAttrib(data_, R_NamesSymbol, names);

auto it = il.begin();
Expand All @@ -876,20 +888,30 @@ inline r_vector<T>::r_vector(std::initializer_list<named_arg> il)
// SAFETY: We've validated type and length ahead of this.
const underlying_type elt = get_elt(value, 0);

// TODO: The equivalent ctor from `initializer_list<r_string>` has a specialization
// for `<r_string>` to translate `elt` to UTF-8 before assigning. Should we have
// that here too? `named_arg` doesn't do any checking here.
if (data_p_ != nullptr) {
data_p_[i] = elt;
if constexpr (std::is_same<T, cpp11::r_string>::value) {
// Translate to UTF-8 before assigning for string types
SEXP translated_elt = Rf_mkCharCE(Rf_translateCharUTF8(elt), CE_UTF8);

if (data_p_ != nullptr) {
data_p_[i] = translated_elt;
} else {
// Handles STRSXP case. VECSXP case has its own specialization.
// We don't expect any ALTREP cases since we just freshly allocated `data_`.
set_elt(data_, i, translated_elt);
}
} else {
// Handles STRSXP case. VECSXP case has its own specialization.
// We don't expect any ALTREP cases since we just freshly allocated `data_`.
set_elt(data_, i, elt);
if (data_p_ != nullptr) {
data_p_[i] = elt;
} else {
set_elt(data_, i, elt);
}
}

SEXP name = Rf_mkCharCE(it->name(), CE_UTF8);
SET_STRING_ELT(names, i, name);
}

UNPROTECT(1);
});
}

Expand Down Expand Up @@ -1156,6 +1178,24 @@ inline typename r_vector<T>::iterator r_vector<T>::find(const r_string& name) co
return end();
}

#ifdef LONG_VECTOR_SUPPORT
template <typename T>
inline T r_vector<T>::value(const int pos) const {
return value(static_cast<R_xlen_t>(pos));
}
#endif

template <typename T>
inline T r_vector<T>::value(const R_xlen_t pos) const {
// Use the parent read-only class's operator[] which returns T directly
return cpp11::r_vector<T>::operator[](pos);
}

template <typename T>
inline T r_vector<T>::value(const size_type pos) const {
return value(static_cast<R_xlen_t>(pos));
}

template <typename T>
inline attribute_proxy<r_vector<T>> r_vector<T>::attr(const char* name) const {
return attribute_proxy<r_vector<T>>(*this, name);
Expand Down
Loading