Skip to content

Commit 37e83e0

Browse files
authored
Merge branch 'cpp11-to-cpp4r' into complex-lean
2 parents 9662aa7 + 3e1116e commit 37e83e0

File tree

5 files changed

+1371
-1466
lines changed

5 files changed

+1371
-1466
lines changed

inst/include/cpp11/as.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,14 @@ template <typename T>
202202
enable_if_c_string<T, T> as_cpp(SEXP from) {
203203
if (Rf_isString(from)) {
204204
if (Rf_xlength(from) == 1) {
205-
// TODO: use vmaxget / vmaxset here?
206-
return {unwind_protect([&] { return Rf_translateCharUTF8(STRING_ELT(from, 0)); })};
205+
void* vmax = vmaxget();
206+
207+
const char* result =
208+
unwind_protect([&] { return Rf_translateCharUTF8(STRING_ELT(from, 0)); });
209+
210+
vmaxset(vmax);
211+
212+
return {result};
207213
}
208214
}
209215

inst/include/cpp11/r_vector.hpp

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
11601200
template <typename T>
11611201
inline 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
14071437
template <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

Comments
 (0)