@@ -235,7 +235,9 @@ class r_vector : public cpp11::r_vector<T> {
235235 proxy at (const r_string& name) const ;
236236
237237 void push_back (T value);
238- // / Implemented in `strings.hpp`
238+ template <typename U = T,
239+ typename std::enable_if<std::is_same<U, r_string>::value>::type* = nullptr >
240+ void push_back (const std::string& value); // Pacha: r_string only (#406)
239241 void push_back (const named_arg& value);
240242 void pop_back ();
241243
@@ -256,6 +258,15 @@ class r_vector : public cpp11::r_vector<T> {
256258
257259 iterator find (const r_string& name) const ;
258260
261+ // / Get the value at position without returning a proxy
262+ // / This is useful when you need the actual value (e.g., for C-style printf functions)
263+ // / that don't trigger implicit conversions from proxy types
264+ #ifdef LONG_VECTOR_SUPPORT
265+ T value (const int pos) const ;
266+ #endif
267+ T value (const R_xlen_t pos) const ;
268+ T value (const size_type pos) const ;
269+
259270 attribute_proxy<r_vector<T>> attr (const char * name) const ;
260271 attribute_proxy<r_vector<T>> attr (const std::string& name) const ;
261272 attribute_proxy<r_vector<T>> attr (SEXP name) const ;
@@ -865,7 +876,8 @@ inline r_vector<T>::r_vector(std::initializer_list<named_arg> il)
865876 }
866877
867878 unwind_protect ([&] {
868- SEXP names = Rf_allocVector (STRSXP, capacity_);
879+ SEXP names;
880+ PROTECT (names = Rf_allocVector (STRSXP, capacity_));
869881 Rf_setAttrib (data_, R_NamesSymbol, names);
870882
871883 auto it = il.begin ();
@@ -876,20 +888,30 @@ inline r_vector<T>::r_vector(std::initializer_list<named_arg> il)
876888 // SAFETY: We've validated type and length ahead of this.
877889 const underlying_type elt = get_elt (value, 0 );
878890
879- // TODO: The equivalent ctor from `initializer_list<r_string>` has a specialization
880- // for `<r_string>` to translate `elt` to UTF-8 before assigning. Should we have
881- // that here too? `named_arg` doesn't do any checking here.
882- if (data_p_ != nullptr ) {
883- data_p_[i] = elt;
891+ if constexpr (std::is_same<T, cpp11::r_string>::value) {
892+ // Translate to UTF-8 before assigning for string types
893+ SEXP translated_elt = Rf_mkCharCE (Rf_translateCharUTF8 (elt), CE_UTF8);
894+
895+ if (data_p_ != nullptr ) {
896+ data_p_[i] = translated_elt;
897+ } else {
898+ // Handles STRSXP case. VECSXP case has its own specialization.
899+ // We don't expect any ALTREP cases since we just freshly allocated `data_`.
900+ set_elt (data_, i, translated_elt);
901+ }
884902 } else {
885- // Handles STRSXP case. VECSXP case has its own specialization.
886- // We don't expect any ALTREP cases since we just freshly allocated `data_`.
887- set_elt (data_, i, elt);
903+ if (data_p_ != nullptr ) {
904+ data_p_[i] = elt;
905+ } else {
906+ set_elt (data_, i, elt);
907+ }
888908 }
889909
890910 SEXP name = Rf_mkCharCE (it->name (), CE_UTF8);
891911 SET_STRING_ELT (names, i, name);
892912 }
913+
914+ UNPROTECT (1 );
893915 });
894916}
895917
@@ -1156,6 +1178,24 @@ inline typename r_vector<T>::iterator r_vector<T>::find(const r_string& name) co
11561178 return end ();
11571179}
11581180
1181+ #ifdef LONG_VECTOR_SUPPORT
1182+ template <typename T>
1183+ inline T r_vector<T>::value(const int pos) const {
1184+ return value (static_cast <R_xlen_t>(pos));
1185+ }
1186+ #endif
1187+
1188+ template <typename T>
1189+ inline T r_vector<T>::value(const R_xlen_t pos) const {
1190+ // Use the parent read-only class's operator[] which returns T directly
1191+ return cpp11::r_vector<T>::operator [](pos);
1192+ }
1193+
1194+ template <typename T>
1195+ inline T r_vector<T>::value(const size_type pos) const {
1196+ return value (static_cast <R_xlen_t>(pos));
1197+ }
1198+
11591199template <typename T>
11601200inline attribute_proxy<r_vector<T>> r_vector<T>::attr(const char * name) const {
11611201 return attribute_proxy<r_vector<T>>(*this , name);
0 commit comments