@@ -236,7 +236,9 @@ class r_vector : public cpp11::r_vector<T> {
236236 proxy at (const r_string& name) const ;
237237
238238 void push_back (T value);
239- // / Implemented in `strings.hpp`
239+ template <typename U = T,
240+ typename std::enable_if<std::is_same<U, r_string>::value>::type* = nullptr >
241+ void push_back (const std::string& value); // Pacha: r_string only (#406)
240242 void push_back (const named_arg& value);
241243 void pop_back ();
242244
@@ -257,6 +259,15 @@ class r_vector : public cpp11::r_vector<T> {
257259
258260 iterator find (const r_string& name) const ;
259261
262+ // / Get the value at position without returning a proxy
263+ // / This is useful when you need the actual value (e.g., for C-style printf functions)
264+ // / that don't trigger implicit conversions from proxy types
265+ #ifdef LONG_VECTOR_SUPPORT
266+ T value (const int pos) const ;
267+ #endif
268+ T value (const R_xlen_t pos) const ;
269+ T value (const size_type pos) const ;
270+
260271 attribute_proxy<r_vector<T>> attr (const char * name) const ;
261272 attribute_proxy<r_vector<T>> attr (const std::string& name) const ;
262273 attribute_proxy<r_vector<T>> attr (SEXP name) const ;
@@ -866,7 +877,8 @@ inline r_vector<T>::r_vector(std::initializer_list<named_arg> il)
866877 }
867878
868879 unwind_protect ([&] {
869- SEXP names = Rf_allocVector (STRSXP, capacity_);
880+ SEXP names;
881+ PROTECT (names = Rf_allocVector (STRSXP, capacity_));
870882 Rf_setAttrib (data_, R_NamesSymbol, names);
871883
872884 auto it = il.begin ();
@@ -877,20 +889,30 @@ inline r_vector<T>::r_vector(std::initializer_list<named_arg> il)
877889 // SAFETY: We've validated type and length ahead of this.
878890 const underlying_type elt = get_elt (value, 0 );
879891
880- // TODO: The equivalent ctor from `initializer_list<r_string>` has a specialization
881- // for `<r_string>` to translate `elt` to UTF-8 before assigning. Should we have
882- // that here too? `named_arg` doesn't do any checking here.
883- if (data_p_ != nullptr ) {
884- data_p_[i] = elt;
892+ if constexpr (std::is_same<T, cpp11::r_string>::value) {
893+ // Translate to UTF-8 before assigning for string types
894+ SEXP translated_elt = Rf_mkCharCE (Rf_translateCharUTF8 (elt), CE_UTF8);
895+
896+ if (data_p_ != nullptr ) {
897+ data_p_[i] = translated_elt;
898+ } else {
899+ // Handles STRSXP case. VECSXP case has its own specialization.
900+ // We don't expect any ALTREP cases since we just freshly allocated `data_`.
901+ set_elt (data_, i, translated_elt);
902+ }
885903 } else {
886- // Handles STRSXP case. VECSXP case has its own specialization.
887- // We don't expect any ALTREP cases since we just freshly allocated `data_`.
888- set_elt (data_, i, elt);
904+ if (data_p_ != nullptr ) {
905+ data_p_[i] = elt;
906+ } else {
907+ set_elt (data_, i, elt);
908+ }
889909 }
890910
891911 SEXP name = Rf_mkCharCE (it->name (), CE_UTF8);
892912 SET_STRING_ELT (names, i, name);
893913 }
914+
915+ UNPROTECT (1 );
894916 });
895917}
896918
@@ -1157,6 +1179,24 @@ inline typename r_vector<T>::iterator r_vector<T>::find(const r_string& name) co
11571179 return end ();
11581180}
11591181
1182+ #ifdef LONG_VECTOR_SUPPORT
1183+ template <typename T>
1184+ inline T r_vector<T>::value(const int pos) const {
1185+ return value (static_cast <R_xlen_t>(pos));
1186+ }
1187+ #endif
1188+
1189+ template <typename T>
1190+ inline T r_vector<T>::value(const R_xlen_t pos) const {
1191+ // Use the parent read-only class's operator[] which returns T directly
1192+ return cpp11::r_vector<T>::operator [](pos);
1193+ }
1194+
1195+ template <typename T>
1196+ inline T r_vector<T>::value(const size_type pos) const {
1197+ return value (static_cast <R_xlen_t>(pos));
1198+ }
1199+
11601200template <typename T>
11611201inline attribute_proxy<r_vector<T>> r_vector<T>::attr(const char * name) const {
11621202 return attribute_proxy<r_vector<T>>(*this , name);
@@ -1393,20 +1433,14 @@ inline SEXP r_vector<T>::resize_names(SEXP x, R_xlen_t size) {
13931433
13941434} // namespace writable
13951435
1396- // TODO: is there a better condition we could use, e.g. assert something true
1397- // rather than three things false?
1398- template <typename C, typename T>
1399- using is_container_but_not_sexp_or_string = typename std::enable_if<
1400- !std::is_constructible<C, SEXP>::value &&
1401- !std::is_same<typename std::decay<C>::type, std::string>::value &&
1402- !std::is_same<typename std::decay<T>::type, std::string>::value &&
1403- // ! Exclude std::complex from being treated as a container
1404- !std::is_same<typename std::decay<C>::type, std::complex <typename std::decay<T>::type>>::value,
1405- typename std::decay<C>::type>::type;
1406-
1436+ // Ensure that C is not constructible from SEXP, and neither C nor T is a std::string
14071437template <typename C, typename T = typename std::decay<C>::type::value_type>
1408- // typename T = typename C::value_type>
1409- is_container_but_not_sexp_or_string<C, T> as_cpp (SEXP from) {
1438+ typename std::enable_if<
1439+ !std::is_constructible<C, SEXP>::value &&
1440+ !std::is_same<typename std::decay<C>::type, std::string>::value &&
1441+ !std::is_same<typename std::decay<T>::type, std::string>::value,
1442+ C>::type
1443+ as_cpp (SEXP from) {
14101444 auto obj = cpp11::r_vector<T>(from);
14111445 return {obj.begin (), obj.end ()};
14121446}
0 commit comments