FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
cpp11/inst/include/cpp11/function.hpp at main · r-lib/cpp11 · GitHub
r-lib
/
cpp11
Public
Notifications
You must be signed in to change notification settings
Fork
52
Star
225
Code
Issues
51
Pull requests
8
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
cpp11
/
inst
/
include
/
cpp11
/
function.hpp
Copy path
More file actions
More file actions
Latest commit
History
History
History
151 lines (122 loc) · 3.97 KB
Breadcrumbs
cpp11
/
inst
/
include
/
cpp11
/
function.hpp
Copy path
File metadata and controls
151 lines (122 loc) · 3.97 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#
pragma
once
#
include
<
cstdio
>
//
for snprintf
#
include
<
cstring
>
//
for strcmp
#
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, stop
#
include
"
cpp11/sexp.hpp
"
//
for sexp
#
ifdef
CPP11_USE_FMT
#
define
FMT_HEADER_ONLY
#
include
"
fmt/core.h
"
#
endif
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>
void
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);
construct_call
(val, std::forward<Args>(args)...);
}
//
Construct the call recursively, each iteration adds an Arg to the pairlist.
template
<
typename
T,
typename
... Args>
void
construct_call
(
SEXP
val,
const
T& arg, Args&&... args)
const
{
SETCAR
(val,
as_sexp
(arg));
val =
CDR
(val);
construct_call
(val, std::forward<Args>(args)...);
}
//
Base case, just return
void
construct_call
(
SEXP
val)
const
{}
};
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
env = safe[detail::r_ns_env](name);
if
(env == R_NilValue) {
stop
(
"
Can't find namespace: '%s'.
"
, name);
}
return
env;
}
//
Either base env or in namespace registry, so no protection needed
SEXP
data_;
};
namespace
detail
{
//
Special internal way to call `base::message()`
//
//
- Pure C, so call with `safe[]`
//
- Holds a `static SEXP` for the `base::message` function protected with
//
`R_PreserveObject()`
//
//
We don't use a `static cpp11::function` because that will infinitely retain a cell in
//
our preserve list, which can throw off our counts in the preserve list tests.
inline
void
r_message
(
const
char
* x) {
static
SEXP
fn =
NULL
;
if
(fn ==
NULL
) {
fn =
Rf_findFun
(
Rf_install
(
"
message
"
), R_BaseEnv);
R_PreserveObject
(fn);
}
SEXP
x_char =
PROTECT
(
Rf_mkCharCE
(x,
CE_UTF8
));
SEXP
x_string =
PROTECT
(
Rf_ScalarString
(x_char));
SEXP
call =
PROTECT
(
Rf_lang2
(fn, x_string));
Rf_eval
(call, R_GlobalEnv);
UNPROTECT
(
3
);
}
}
//
namespace detail
inline
void
message
(
const
char
* fmt_arg) {
#
ifdef
CPP11_USE_FMT
std::string msg =
fmt::format
(
fmt::runtime
(fmt_arg));
safe[detail::r_message](msg.
c_str
());
#
else
char
buff[
1024
];
int
msg;
msg =
std::snprintf
(buff,
1024
,
"
%s
"
, fmt_arg);
if
(msg >=
0
&& msg <
1024
) {
safe[detail::r_message](buff);
}
#
endif
}
template
<
typename
... Args>
void
message
(
const
char
* fmt_arg, Args... args) {
#
ifdef
CPP11_USE_FMT
std::string msg =
fmt::format
(
fmt::runtime
(fmt_arg), args...);
safe[detail::r_message](msg.
c_str
());
#
else
char
buff[
1024
];
int
msg;
msg =
std::snprintf
(buff,
1024
, fmt_arg, args...);
if
(msg >=
0
&& msg <
1024
) {
safe[detail::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
Back
|
FazBrowse Home
|
New Git URL