diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/arrow/r/inst/include/cpp11/as.hpp | |
parent | Initial commit. (diff) | |
download | ceph-upstream/18.2.2.tar.xz ceph-upstream/18.2.2.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/arrow/r/inst/include/cpp11/as.hpp')
-rw-r--r-- | src/arrow/r/inst/include/cpp11/as.hpp | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/src/arrow/r/inst/include/cpp11/as.hpp b/src/arrow/r/inst/include/cpp11/as.hpp new file mode 100644 index 000000000..dd9641a16 --- /dev/null +++ b/src/arrow/r/inst/include/cpp11/as.hpp @@ -0,0 +1,337 @@ +// cpp11 version: 0.3.1.1 +// vendored on: 2021-08-11 +#pragma once + +#include <cmath> // for modf +#include <initializer_list> // for initializer_list +#include <memory> // for std::shared_ptr, std::weak_ptr, std::unique_ptr +#include <string> // for string, basic_string +#include <type_traits> // for decay, enable_if, is_same, is_convertible + +#include "cpp11/R.hpp" // for SEXP, SEXPREC, Rf_xlength, R_xlen_t +#include "cpp11/protect.hpp" // for stop, protect, safe, protect::function + +namespace cpp11 { + +template <bool C, typename R = void> +using enable_if_t = typename std::enable_if<C, R>::type; + +template <typename T> +using decay_t = typename std::decay<T>::type; + +template <typename T> +struct is_smart_ptr : std::false_type {}; + +template <typename T> +struct is_smart_ptr<std::shared_ptr<T>> : std::true_type {}; + +template <typename T> +struct is_smart_ptr<std::unique_ptr<T>> : std::true_type {}; + +template <typename T> +struct is_smart_ptr<std::weak_ptr<T>> : std::true_type {}; + +template <typename T, typename R = void> +using enable_if_constructible_from_sexp = + enable_if_t<!is_smart_ptr<T>::value && // workaround for gcc 4.8 + std::is_class<T>::value && std::is_constructible<T, SEXP>::value, + R>; + +template <typename T, typename R = void> +using enable_if_is_sexp = enable_if_t<std::is_same<T, SEXP>::value, R>; + +template <typename T, typename R = void> +using enable_if_convertible_to_sexp = enable_if_t<std::is_convertible<T, SEXP>::value, R>; + +template <typename T, typename R = void> +using disable_if_convertible_to_sexp = + enable_if_t<!std::is_convertible<T, SEXP>::value, R>; + +template <typename T, typename R = void> +using enable_if_integral = + enable_if_t<std::is_integral<T>::value && !std::is_same<T, bool>::value && + !std::is_same<T, char>::value, + R>; + +template <typename T, typename R = void> +using enable_if_floating_point = + typename std::enable_if<std::is_floating_point<T>::value, R>::type; + +template <typename E, typename R = void> +using enable_if_enum = enable_if_t<std::is_enum<E>::value, R>; + +template <typename T, typename R = void> +using enable_if_bool = enable_if_t<std::is_same<T, bool>::value, R>; + +template <typename T, typename R = void> +using enable_if_char = enable_if_t<std::is_same<T, char>::value, R>; + +template <typename T, typename R = void> +using enable_if_std_string = enable_if_t<std::is_same<T, std::string>::value, R>; + +template <typename T, typename R = void> +using enable_if_c_string = enable_if_t<std::is_same<T, const char*>::value, R>; + +// https://stackoverflow.com/a/1521682/2055486 +// +inline bool is_convertable_without_loss_to_integer(double value) { + double int_part; + return std::modf(value, &int_part) == 0.0; +} + +template <typename T> +enable_if_constructible_from_sexp<T, T> as_cpp(SEXP from) { + return T(from); +} + +template <typename T> +enable_if_is_sexp<T, T> as_cpp(SEXP from) { + return from; +} + +template <typename T> +enable_if_integral<T, T> as_cpp(SEXP from) { + if (Rf_isInteger(from)) { + if (Rf_xlength(from) == 1) { + return INTEGER_ELT(from, 0); + } + } else if (Rf_isReal(from)) { + if (Rf_xlength(from) == 1) { + if (ISNA(REAL_ELT(from, 0))) { + return NA_INTEGER; + } + double value = REAL_ELT(from, 0); + if (is_convertable_without_loss_to_integer(value)) { + return value; + } + } + } else if (Rf_isLogical(from)) { + if (Rf_xlength(from) == 1) { + if (LOGICAL_ELT(from, 0) == NA_LOGICAL) { + return NA_INTEGER; + } + } + } + + stop("Expected single integer value"); +} + +template <typename E> +enable_if_enum<E, E> as_cpp(SEXP from) { + if (Rf_isInteger(from)) { + using underlying_type = typename std::underlying_type<E>::type; + using int_type = typename std::conditional<std::is_same<char, underlying_type>::value, + int, // as_cpp<char> would trigger + // undesired string conversions + underlying_type>::type; + return static_cast<E>(as_cpp<int_type>(from)); + } + + stop("Expected single integer value"); +} + +template <typename T> +enable_if_bool<T, T> as_cpp(SEXP from) { + if (Rf_isLogical(from)) { + if (Rf_xlength(from) == 1) { + return LOGICAL_ELT(from, 0) == 1; + } + } + + stop("Expected single logical value"); +} + +template <typename T> +enable_if_floating_point<T, T> as_cpp(SEXP from) { + if (Rf_isReal(from)) { + if (Rf_xlength(from) == 1) { + return REAL_ELT(from, 0); + } + } + // All 32 bit integers can be coerced to doubles, so we just convert them. + if (Rf_isInteger(from)) { + if (Rf_xlength(from) == 1) { + if (INTEGER_ELT(from, 0) == NA_INTEGER) { + return NA_REAL; + } + return INTEGER_ELT(from, 0); + } + } + + // Also allow NA values + if (Rf_isLogical(from)) { + if (Rf_xlength(from) == 1) { + if (LOGICAL_ELT(from, 0) == NA_LOGICAL) { + return NA_REAL; + } + } + } + + stop("Expected single double value"); +} + +template <typename T> +enable_if_char<T, T> as_cpp(SEXP from) { + if (Rf_isString(from)) { + if (Rf_xlength(from) == 1) { + return unwind_protect([&] { return Rf_translateCharUTF8(STRING_ELT(from, 0))[0]; }); + } + } + + stop("Expected string vector of length 1"); +} + +template <typename T> +enable_if_c_string<T, T> as_cpp(SEXP from) { + if (Rf_isString(from)) { + if (Rf_xlength(from) == 1) { + // TODO: use vmaxget / vmaxset here? + return {unwind_protect([&] { return Rf_translateCharUTF8(STRING_ELT(from, 0)); })}; + } + } + + stop("Expected string vector of length 1"); +} + +template <typename T> +enable_if_std_string<T, T> as_cpp(SEXP from) { + return {as_cpp<const char*>(from)}; +} + +/// Temporary workaround for compatibility with cpp11 0.1.0 +template <typename T> +enable_if_t<!std::is_same<decay_t<T>, T>::value, decay_t<T>> as_cpp(SEXP from) { + return as_cpp<decay_t<T>>(from); +} + +template <typename T> +enable_if_integral<T, SEXP> as_sexp(T from) { + return safe[Rf_ScalarInteger](from); +} + +template <typename T> +enable_if_floating_point<T, SEXP> as_sexp(T from) { + return safe[Rf_ScalarReal](from); +} + +template <typename T> +enable_if_bool<T, SEXP> as_sexp(T from) { + return safe[Rf_ScalarLogical](from); +} + +template <typename T> +enable_if_c_string<T, SEXP> as_sexp(T from) { + return unwind_protect([&] { return Rf_ScalarString(Rf_mkCharCE(from, CE_UTF8)); }); +} + +template <typename T> +enable_if_std_string<T, SEXP> as_sexp(const T& from) { + return as_sexp(from.c_str()); +} + +template <typename Container, typename T = typename Container::value_type, + typename = disable_if_convertible_to_sexp<Container>> +enable_if_integral<T, SEXP> as_sexp(const Container& from) { + R_xlen_t size = from.size(); + SEXP data = safe[Rf_allocVector](INTSXP, size); + + auto it = from.begin(); + int* data_p = INTEGER(data); + for (R_xlen_t i = 0; i < size; ++i, ++it) { + data_p[i] = *it; + } + return data; +} + +inline SEXP as_sexp(std::initializer_list<int> from) { + return as_sexp<std::initializer_list<int>>(from); +} + +template <typename Container, typename T = typename Container::value_type, + typename = disable_if_convertible_to_sexp<Container>> +enable_if_floating_point<T, SEXP> as_sexp(const Container& from) { + R_xlen_t size = from.size(); + SEXP data = safe[Rf_allocVector](REALSXP, size); + + auto it = from.begin(); + double* data_p = REAL(data); + for (R_xlen_t i = 0; i < size; ++i, ++it) { + data_p[i] = *it; + } + return data; +} + +inline SEXP as_sexp(std::initializer_list<double> from) { + return as_sexp<std::initializer_list<double>>(from); +} + +template <typename Container, typename T = typename Container::value_type, + typename = disable_if_convertible_to_sexp<Container>> +enable_if_bool<T, SEXP> as_sexp(const Container& from) { + R_xlen_t size = from.size(); + SEXP data = safe[Rf_allocVector](LGLSXP, size); + + auto it = from.begin(); + int* data_p = LOGICAL(data); + for (R_xlen_t i = 0; i < size; ++i, ++it) { + data_p[i] = *it; + } + return data; +} + +inline SEXP as_sexp(std::initializer_list<bool> from) { + return as_sexp<std::initializer_list<bool>>(from); +} + +namespace detail { +template <typename Container, typename AsCstring> +SEXP as_sexp_strings(const Container& from, AsCstring&& c_str) { + R_xlen_t size = from.size(); + + SEXP data; + try { + data = PROTECT(safe[Rf_allocVector](STRSXP, size)); + + auto it = from.begin(); + for (R_xlen_t i = 0; i < size; ++i, ++it) { + SET_STRING_ELT(data, i, safe[Rf_mkCharCE](c_str(*it), CE_UTF8)); + } + } catch (const unwind_exception& e) { + UNPROTECT(1); + throw e; + } + + UNPROTECT(1); + return data; +} +} // namespace detail + +class r_string; + +template <typename T, typename R = void> +using disable_if_r_string = enable_if_t<!std::is_same<T, cpp11::r_string>::value, R>; + +template <typename Container, typename T = typename Container::value_type, + typename = disable_if_r_string<T>> +enable_if_t<std::is_convertible<T, std::string>::value && + !std::is_convertible<T, const char*>::value, + SEXP> +as_sexp(const Container& from) { + return detail::as_sexp_strings(from, [](const std::string& s) { return s.c_str(); }); +} + +template <typename Container, typename T = typename Container::value_type> +enable_if_c_string<T, SEXP> as_sexp(const Container& from) { + return detail::as_sexp_strings(from, [](const char* s) { return s; }); +} + +inline SEXP as_sexp(std::initializer_list<const char*> from) { + return as_sexp<std::initializer_list<const char*>>(from); +} + +template <typename T, typename = disable_if_r_string<T>> +enable_if_convertible_to_sexp<T, SEXP> as_sexp(const T& from) { + return from; +} + +} // namespace cpp11 |