forked from r-lib/cpp11
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfunction.hpp
More file actions
116 lines (95 loc) · 3.11 KB
/
function.hpp
File metadata and controls
116 lines (95 loc) · 3.11 KB
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#pragma once
#include <string.h> // for strcmp
#include <cstdio> // for snprintf
#include <string> // for string, basic_string
#include <utility> // for forward
#include "cpp11/R.hpp" // for SEXP, SEXPREC, CDR, Rf_install, SETCAR
#include "cpp11/as.hpp" // for as_sexp
#include "cpp11/named_arg.hpp" // for named_arg
#include "cpp11/protect.hpp" // for protect, protect::function, safe
#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)) {}
package(const std::string& name) : data_(get_namespace(name.c_str())) {}
function operator[](const char* name) {
return safe[Rf_findFun](safe[Rf_install](name), data_);
}
function operator[](const std::string& name) { return operator[](name.c_str()); }
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_;
};
inline void message(const char* fmt_arg) {
static auto R_message = cpp11::package("base")["message"];
#ifdef CPP11_USE_FMT
std::string msg = fmt::format(fmt_arg);
R_message(msg.c_str());
#else
char buff[1024];
int msg;
msg = std::snprintf(buff, 1024, "%s", fmt_arg);
if (msg >= 0 && msg < 1024) {
R_message(buff);
}
#endif
}
template <typename... Args>
void message(const char* fmt_arg, Args... args) {
static auto R_message = cpp11::package("base")["message"];
#ifdef CPP11_USE_FMT
std::string msg = fmt::format(fmt_arg, args...);
R_message(msg.c_str());
#else
char buff[1024];
int msg;
msg = std::snprintf(buff, 1024, fmt_arg, args...);
if (msg >= 0 && msg < 1024) {
R_message(buff);
}
#endif
}
inline void message(const std::string& fmt_arg) { message(fmt_arg.c_str()); }
template <typename... Args>
void message(const std::string& fmt_arg, Args... args) {
message(fmt_arg.c_str(), args...);
}
} // namespace cpp11