-
Notifications
You must be signed in to change notification settings - Fork 292
Expand file tree
/
Copy pathmap.c
More file actions
212 lines (177 loc) · 5.01 KB
/
map.c
File metadata and controls
212 lines (177 loc) · 5.01 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
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#define R_NO_REMAP
#include <R.h>
#include <Rversion.h>
#include <Rinternals.h>
#include "coerce.h"
#include "conditions.h"
#include "utils.h"
// Including <cli/progress.h> before "cleancall.h" because we want to register
// exiting handlers ourselves, rather than letting cli register them for us.
#include <cli/progress.h>
#include "cleancall.h"
static
void cb_progress_done(void* bar_ptr) {
SEXP bar = (SEXP)bar_ptr;
cli_progress_done(bar);
R_ReleaseObject(bar);
}
// call must involve i
SEXP call_loop(SEXP env,
SEXP call,
SEXPTYPE type,
SEXP progress,
int n,
SEXP names,
int* p_i,
int force) {
SEXP bar = cli_progress_bar(n, progress);
R_PreserveObject(bar);
r_call_on_exit((void (*)(void*)) cb_progress_done, (void*) bar);
SEXP out = PROTECT(Rf_allocVector(type, n));
Rf_setAttrib(out, R_NamesSymbol, names);
for (int i = 0; i < n; ++i) {
*p_i = i + 1;
if (CLI_SHOULD_TICK) {
cli_progress_set(bar, i);
}
if (i % 1024 == 0) {
R_CheckUserInterrupt();
}
SEXP res = PROTECT(R_forceAndCall(call, force, env));
if (type != VECSXP && Rf_length(res) != 1) {
Rf_errorcall(R_NilValue, "Result must be length 1, not %i.", Rf_length(res));
}
set_vector_value(out, i, res, 0);
UNPROTECT(1);
}
*p_i = 0;
UNPROTECT(1);
return out;
}
SEXP map_impl(SEXP env,
SEXP ffi_type,
SEXP progress,
SEXP ffi_n,
SEXP names,
SEXP i) {
static SEXP call = NULL;
if (call == NULL) {
SEXP x_sym = Rf_install(".x");
SEXP f_sym = Rf_install(".f");
SEXP i_sym = Rf_install("i");
// Constructs a call like f(x[[i]], ...) - don't want to substitute
// actual values for f or x, because they may be long, which creates
// bad tracebacks()
SEXP x_i_sym = PROTECT(Rf_lang3(R_Bracket2Symbol, x_sym, i_sym));
call = Rf_lang3(f_sym, x_i_sym, R_DotsSymbol);
R_PreserveObject(call);
UNPROTECT(1);
}
SEXPTYPE type = Rf_str2type(CHAR(STRING_ELT(ffi_type, 0)));
int n = INTEGER_ELT(ffi_n, 0);
int* p_i = INTEGER(i);
int force = 1;
return call_loop(
env,
call,
type,
progress,
n,
names,
p_i,
force
);
}
SEXP map2_impl(SEXP env,
SEXP ffi_type,
SEXP progress,
SEXP ffi_n,
SEXP names,
SEXP i) {
static SEXP call = NULL;
if (call == NULL) {
SEXP x_sym = Rf_install(".x");
SEXP y_sym = Rf_install(".y");
SEXP f_sym = Rf_install(".f");
SEXP i_sym = Rf_install("i");
// Constructs a call like f(x[[i]], y[[i]], ...)
SEXP x_i_sym = PROTECT(Rf_lang3(R_Bracket2Symbol, x_sym, i_sym));
SEXP y_i_sym = PROTECT(Rf_lang3(R_Bracket2Symbol, y_sym, i_sym));
call = Rf_lang4(f_sym, x_i_sym, y_i_sym, R_DotsSymbol);
R_PreserveObject(call);
UNPROTECT(2);
}
SEXPTYPE type = Rf_str2type(CHAR(STRING_ELT(ffi_type, 0)));
int n = INTEGER_ELT(ffi_n, 0);
int* p_i = INTEGER(i);
int force = 2;
return call_loop(
env,
call,
type,
progress,
n,
names,
p_i,
force
);
}
SEXP pmap_impl(SEXP env,
SEXP ffi_type,
SEXP progress,
SEXP ffi_n,
SEXP names,
SEXP i,
SEXP call_names,
SEXP ffi_call_n) {
// Construct call like f(.l[[1]][[i]], .l[[2]][[i]], ...)
//
// Currently accessing S3 vectors in a list like .l[[c(1, i)]] will not
// preserve the class (cf. #358).
//
// We construct the call backwards because can only add to the front of a
// linked list. That makes PROTECTion tricky because we need to update it
// each time to point to the start of the linked list.
SEXP l_sym = Rf_install(".l");
SEXP f_sym = Rf_install(".f");
SEXP i_sym = Rf_install("i");
SEXP call = Rf_lang1(R_DotsSymbol);
PROTECT_INDEX call_shelter;
PROTECT_WITH_INDEX(call, &call_shelter);
bool has_call_names = call_names != R_NilValue;
const SEXP* v_call_names = has_call_names ? STRING_PTR_RO(call_names) : NULL;
int call_n = INTEGER_ELT(ffi_call_n, 0);
for (int j = call_n - 1; j >= 0; --j) {
// Construct call like .l[[j]][[i]]
SEXP j_val = PROTECT(Rf_ScalarInteger(j + 1));
SEXP l_j_sym = PROTECT(Rf_lang3(R_Bracket2Symbol, l_sym, j_val));
SEXP l_j_i_sym = PROTECT(Rf_lang3(R_Bracket2Symbol, l_j_sym, i_sym));
call = Rf_lcons(l_j_i_sym, call);
REPROTECT(call, call_shelter);
if (has_call_names) {
const char* call_name = CHAR(v_call_names[j]);
if (call_name[0] != '\0') {
SET_TAG(call, Rf_install(call_name));
}
}
UNPROTECT(3);
}
call = Rf_lcons(f_sym, call);
REPROTECT(call, call_shelter);
SEXPTYPE type = Rf_str2type(CHAR(STRING_ELT(ffi_type, 0)));
int n = INTEGER_ELT(ffi_n, 0);
int* p_i = INTEGER(i);
int force = call_n;
SEXP out = call_loop(
env,
call,
type,
progress,
n,
names,
p_i,
force
);
UNPROTECT(1);
return out;
}