-
Notifications
You must be signed in to change notification settings - Fork 46
/
function.hpp
69 lines (55 loc) · 1.85 KB
/
function.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#pragma once
#include <string.h> // for strcmp
#include <type_traits> // for forward
#include "cpp11/named_arg.hpp" // for named_arg
#include "cpp11/protect.hpp" // for SEXP, SEXPREC, protect, protect::fu...
#include "cpp11/sexp.hpp" // for sexp
namespace cpp11 {
class function {
public:
function(SEXP data) : data_(data) {}
template <typename... Args>
sexp operator()(Args&&... args) const {
// Size of the arguments plus one for the function name itself
R_xlen_t num_args = sizeof...(args) + 1;
sexp call(safe[Rf_allocVector](LANGSXP, num_args));
construct_call(call, data_, std::forward<Args>(args)...);
return safe[Rf_eval](call, R_GlobalEnv);
}
private:
SEXP data_;
template <typename... Args>
SEXP construct_call(SEXP val, const named_arg& arg, Args&&... args) const {
SETCAR(val, arg.value());
SET_TAG(val, safe[Rf_install](arg.name()));
val = CDR(val);
return construct_call(val, std::forward<Args>(args)...);
}
// Construct the call recursively, each iteration adds an Arg to the pairlist.
// We need
template <typename T, typename... Args>
SEXP construct_call(SEXP val, const T& arg, Args&&... args) const {
SETCAR(val, as_sexp(arg));
val = CDR(val);
return construct_call(val, std::forward<Args>(args)...);
}
// Base case, just return
SEXP construct_call(SEXP val) const { return val; }
};
class package {
public:
package(const char* name) : data_(get_namespace(name)) {}
function operator[](const char* name) {
return safe[Rf_findFun](safe[Rf_install](name), data_);
}
private:
static SEXP get_namespace(const char* name) {
if (strcmp(name, "base") == 0) {
return R_BaseEnv;
}
sexp name_sexp = safe[Rf_install](name);
return safe[Rf_findVarInFrame](R_NamespaceRegistry, name_sexp);
}
SEXP data_;
};
} // namespace cpp11