/src/r-source/src/main/subset.c
Line | Count | Source |
1 | | /* |
2 | | * R : A Computer Language for Statistical Data Analysis |
3 | | * Copyright (C) 1997--2026 The R Core Team |
4 | | * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, a copy is available at |
18 | | * https://www.R-project.org/Licenses/ |
19 | | * |
20 | | * |
21 | | * Vector and List Subsetting |
22 | | * |
23 | | * There are three kinds of subscripting [, [[, and $. |
24 | | * We have three different functions to compute these. |
25 | | * |
26 | | * |
27 | | * Note on Matrix Subscripts |
28 | | * |
29 | | * The special [ subscripting where dim(x) == ncol(subscript matrix) |
30 | | * is handled inside VectorSubset. The subscript matrix is turned |
31 | | * into a subscript vector of the appropriate size and then |
32 | | * VectorSubset continues. This provides coherence especially |
33 | | * regarding attributes etc. (it would be quicker to handle this case |
34 | | * separately, but then we would have more to keep in step. |
35 | | */ |
36 | | |
37 | | #ifdef HAVE_CONFIG_H |
38 | | #include <config.h> |
39 | | #endif |
40 | | |
41 | | #include <Defn.h> |
42 | | #include <Internal.h> |
43 | | |
44 | | /* JMC convinced MM that this was not a good idea: */ |
45 | | #undef _S4_subsettable |
46 | | |
47 | | |
48 | 1.58M | static R_INLINE SEXP VECTOR_ELT_FIX_NAMED(SEXP y, R_xlen_t i) { |
49 | | /* if RHS (container or element) has NAMED > 0 set NAMED = NAMEDMAX. |
50 | | Duplicating might be safer/more consistent (fix bug reported by |
51 | | Radford Neal; similar to PR15098) */ |
52 | 1.58M | SEXP val = VECTOR_ELT(y, i); |
53 | 1.58M | if ((NAMED(y) || NAMED(val))) |
54 | 1.58M | ENSURE_NAMEDMAX(val); |
55 | 1.58M | return val; |
56 | 1.58M | } |
57 | | |
58 | | /* ExtractSubset allocates "result" and does the transfer of elements |
59 | | from "x" to "result" according to the integer/real subscripts given |
60 | | in "indx". |
61 | | |
62 | | The EXTRACT_SUBSET_LOOP macro allows the branches based on index |
63 | | type and vector type to happen outside the loop. |
64 | | |
65 | | This could avoid using data pointers, but there is little point as |
66 | | currently the subscript code forces allocation. |
67 | | */ |
68 | | |
69 | 14.3M | #define EXTRACT_SUBSET_LOOP(STDCODE, NACODE) do { \ |
70 | 14.3M | if (TYPEOF(indx) == INTSXP) { \ |
71 | 13.9M | const int *pindx = INTEGER_RO(indx); \ |
72 | 140M | for (i = 0; i < n; i++) { \ |
73 | 126M | ii = pindx[i]; \ |
74 | 126M | if (0 < ii && ii <= nx) { \ |
75 | 123M | ii--; \ |
76 | 123M | STDCODE; \ |
77 | 123M | } \ |
78 | 126M | else /* out of bounds or NA */ \ |
79 | 126M | NACODE; \ |
80 | 126M | } \ |
81 | 13.9M | } \ |
82 | 14.3M | else { \ |
83 | 382k | const double *pindx = REAL_RO(indx); \ |
84 | 1.00M | for (i = 0; i < n; i++) { \ |
85 | 626k | double di = pindx[i]; \ |
86 | 626k | ii = (R_xlen_t) (di - 1); \ |
87 | 626k | if (R_FINITE(di) && \ |
88 | 626k | 0 <= ii && ii < nx) \ |
89 | 626k | STDCODE; \ |
90 | 626k | else \ |
91 | 626k | NACODE; \ |
92 | 626k | } \ |
93 | 382k | } \ |
94 | 14.3M | } while (0) |
95 | | |
96 | | NORET static void errorcallNotSubsettable(SEXP x, SEXP call) |
97 | 7 | { |
98 | 7 | SEXP cond = R_makeNotSubsettableError(x, call); |
99 | 7 | PROTECT(cond); |
100 | 7 | R_signalErrorCondition(cond, call); |
101 | 7 | UNPROTECT(1); /* cond; not reached */ |
102 | 7 | } |
103 | | |
104 | | NORET static void errorcallMissingSubs(SEXP x, SEXP call) |
105 | 1 | { |
106 | 1 | if (call == R_NilValue) |
107 | 0 | call = R_CurrentExpression; |
108 | 1 | SEXP cond = R_makeMissingSubscriptError(x, call); |
109 | 1 | PROTECT(cond); |
110 | 1 | R_signalErrorCondition(cond, call); |
111 | 1 | UNPROTECT(1); /* cond; not reached */ |
112 | 1 | } |
113 | | |
114 | | |
115 | | attribute_hidden SEXP ExtractSubset(SEXP x, SEXP indx, SEXP call) |
116 | 14.4M | { |
117 | 14.4M | if (x == R_NilValue) |
118 | 148k | return x; |
119 | | |
120 | 14.3M | SEXP result; |
121 | | |
122 | 14.3M | if (ALTREP(x)) { |
123 | 3.87k | result = ALTVEC_EXTRACT_SUBSET(x, indx, call); |
124 | 3.87k | if (result != NULL) |
125 | 105 | return result; |
126 | 3.87k | } |
127 | | |
128 | 14.3M | R_xlen_t i, ii, n, nx; |
129 | 14.3M | n = XLENGTH(indx); |
130 | 14.3M | nx = xlength(x); |
131 | 14.3M | int mode = TYPEOF(x); |
132 | | |
133 | | /* protect allocation in case _ELT operations need to allocate */ |
134 | 14.3M | PROTECT(result = allocVector(mode, n)); |
135 | 14.3M | switch(mode) { |
136 | 62.8k | case LGLSXP: |
137 | 62.8k | EXTRACT_SUBSET_LOOP(LOGICAL0(result)[i] = LOGICAL_ELT(x, ii), |
138 | 62.8k | LOGICAL0(result)[i] = NA_INTEGER); |
139 | 62.8k | break; |
140 | 2.90M | case INTSXP: |
141 | 2.90M | EXTRACT_SUBSET_LOOP(INTEGER0(result)[i] = INTEGER_ELT(x, ii), |
142 | 2.90M | INTEGER0(result)[i] = NA_INTEGER); |
143 | 2.90M | break; |
144 | 3.00M | case REALSXP: |
145 | 3.00M | EXTRACT_SUBSET_LOOP(REAL0(result)[i] = REAL_ELT(x, ii), |
146 | 3.00M | REAL0(result)[i] = NA_REAL); |
147 | 3.00M | break; |
148 | 1.09k | case CPLXSXP: |
149 | 1.09k | { |
150 | 1.09k | Rcomplex NA_CPLX = { .r = NA_REAL, .i = NA_REAL }; |
151 | 1.09k | EXTRACT_SUBSET_LOOP(COMPLEX0(result)[i] = COMPLEX_ELT(x, ii), |
152 | 1.09k | COMPLEX0(result)[i] = NA_CPLX); |
153 | 1.09k | } |
154 | 1.09k | break; |
155 | 7.64M | case STRSXP: |
156 | 7.64M | EXTRACT_SUBSET_LOOP(SET_STRING_ELT(result, i, STRING_ELT(x, ii)), |
157 | 7.64M | SET_STRING_ELT(result, i, NA_STRING)); |
158 | 7.64M | break; |
159 | 730k | case VECSXP: |
160 | 730k | case EXPRSXP: |
161 | 730k | EXTRACT_SUBSET_LOOP(SET_VECTOR_ELT(result, i, |
162 | 730k | VECTOR_ELT_FIX_NAMED(x, ii)), |
163 | 730k | SET_VECTOR_ELT(result, i, R_NilValue)); |
164 | 730k | break; |
165 | 58 | case RAWSXP: |
166 | 58 | EXTRACT_SUBSET_LOOP(RAW0(result)[i] = RAW_ELT(x, ii), |
167 | 58 | RAW0(result)[i] = (Rbyte) 0); |
168 | 58 | break; |
169 | 0 | case LISTSXP: |
170 | | /* cannot happen: pairlists are coerced to lists */ |
171 | 0 | case LANGSXP: |
172 | | /* cannot happen: LANGSXPs are coerced to lists */ |
173 | 0 | default: |
174 | 0 | errorcallNotSubsettable(x, call); |
175 | 14.3M | } |
176 | 14.3M | UNPROTECT(1); /* result */ |
177 | 14.3M | return result; |
178 | 14.3M | } |
179 | | |
180 | | |
181 | | /* This is for all cases with a single index, including 1D arrays and |
182 | | matrix indexing of arrays */ |
183 | | static SEXP VectorSubset(SEXP x, SEXP s, SEXP call) |
184 | 14.1M | { |
185 | 14.1M | if (s == R_MissingArg) return duplicate(x); |
186 | | |
187 | | /* Check to see if we have special matrix subscripting. */ |
188 | | /* If we do, make a real subscript vector and protect it. */ |
189 | | |
190 | 14.1M | PROTECT(s); |
191 | 14.1M | if (ATTRIB(s) != R_NilValue) { /* pretest to speed up simple case */ |
192 | 71.1k | SEXP dim = getAttrib(x, R_DimSymbol); |
193 | 71.1k | if (isMatrix(s) && isArray(x) && ncols(s) == length(dim)) { |
194 | 0 | if (isString(s)) { |
195 | 0 | SEXP dnames = PROTECT(GetArrayDimnames(x)); |
196 | 0 | s = strmat2intmat(s, dnames, call, x); |
197 | 0 | UNPROTECT(2); /* dnames, s */ |
198 | 0 | PROTECT(s); |
199 | 0 | } |
200 | 0 | if (isInteger(s) || isReal(s)) { |
201 | 0 | s = mat2indsub(dim, s, call, x); |
202 | 0 | UNPROTECT(1); |
203 | 0 | PROTECT(s); |
204 | 0 | } |
205 | 0 | } |
206 | 71.1k | } |
207 | | |
208 | | /* Convert to a vector of integer subscripts */ |
209 | | /* in the range 1:length(x). */ |
210 | 14.1M | R_xlen_t stretch = 1; |
211 | 14.1M | SEXP indx = PROTECT(makeSubscript(x, s, &stretch, call)); |
212 | | |
213 | | /* Allocate the result. */ |
214 | | |
215 | 14.1M | int mode = TYPEOF(x); |
216 | 14.1M | SEXP result = PROTECT(ExtractSubset(x, indx, call)); |
217 | 14.1M | if (mode == VECSXP || mode == EXPRSXP) |
218 | | /* we do not duplicate the values when extracting the subset, |
219 | | so to be conservative mark the result as NAMED = NAMEDMAX */ |
220 | 730k | ENSURE_NAMEDMAX(result); |
221 | | |
222 | 14.1M | if (result != R_NilValue) { |
223 | 14.1M | SEXP attrib, nattrib; |
224 | 14.1M | if ( |
225 | 14.1M | ((attrib = getAttrib(x, R_NamesSymbol)) != R_NilValue) || |
226 | 14.0M | ( /* here we might have an array. Use row names if 1D */ |
227 | 14.0M | isArray(x) && length(getAttrib(x, R_DimNamesSymbol)) == 1 && |
228 | 0 | (attrib = getAttrib(x, R_DimNamesSymbol)) != R_NilValue && |
229 | 0 | (attrib = GetRowNames(attrib)) != R_NilValue |
230 | 14.0M | ) |
231 | 14.1M | ) { |
232 | 86.1k | PROTECT(attrib); |
233 | 86.1k | PROTECT(nattrib = ExtractSubset(attrib, indx, call)); |
234 | 86.1k | setAttrib(result, R_NamesSymbol, nattrib); |
235 | 86.1k | UNPROTECT(2); /* attrib, nattrib */ |
236 | 86.1k | } |
237 | 14.1M | if ((attrib = getAttrib(x, R_SrcrefSymbol)) != R_NilValue && |
238 | 0 | TYPEOF(attrib) == VECSXP) { |
239 | 0 | PROTECT(nattrib = ExtractSubset(attrib, indx, call)); |
240 | 0 | setAttrib(result, R_SrcrefSymbol, nattrib); |
241 | 0 | UNPROTECT(1); |
242 | 0 | } |
243 | | /* FIXME: this is wrong, because the slots are gone, so result is an invalid object of the S4 class! JMC 3/3/09 */ |
244 | | #ifdef _S4_subsettable |
245 | | if(IS_S4_OBJECT(x)) { /* e.g. contains = "list" */ |
246 | | setAttrib(result, R_ClassSymbol, getAttrib(x, R_ClassSymbol)); |
247 | | SET_S4_OBJECT(result); |
248 | | } |
249 | | #endif |
250 | 14.1M | } |
251 | 14.1M | UNPROTECT(3); |
252 | 14.1M | return result; |
253 | 14.1M | } |
254 | | |
255 | | NORET static void errorcallOutOfBounds(SEXP x, int subscript, |
256 | | R_xlen_t index, SEXP call) |
257 | 0 | { |
258 | 0 | SEXP sindex = ScalarReal((double) index); |
259 | 0 | PROTECT(sindex); |
260 | 0 | SEXP cond = R_makeOutOfBoundsError(x, subscript, sindex, call, NULL); |
261 | 0 | PROTECT(cond); |
262 | 0 | R_signalErrorCondition(cond, call); |
263 | 0 | UNPROTECT(2); /* sindex, cond; not reached */ |
264 | 0 | } |
265 | | |
266 | | NORET static void errorcallOutOfBoundsSEXP(SEXP x, int subscript, |
267 | | SEXP sindex, SEXP call) |
268 | 17 | { |
269 | 17 | SEXP cond = R_makeOutOfBoundsError(x, subscript, sindex, call, NULL); |
270 | 17 | PROTECT(cond); |
271 | 17 | R_signalErrorCondition(cond, call); |
272 | 17 | UNPROTECT(1); /* cond; not reached */ |
273 | 17 | } |
274 | | |
275 | | // in ./subscript.c : |
276 | | SEXP int_arraySubscript(int dim, SEXP s, SEXP dims, SEXP x, SEXP call); |
277 | | |
278 | | /* The MATRIX_SUBSET_LOOP macro allows the branches based on index |
279 | | type and vector type to happen outside the loop. Running through |
280 | | the indices in column-major order also improves cache locality. */ |
281 | | |
282 | 145k | #define MATRIX_SUBSET_LOOP(STDCODE, NACODE) do { \ |
283 | 292k | for (j = 0; j < ncs; j++) { \ |
284 | 147k | jj = psc[j]; \ |
285 | 147k | if (jj != NA_INTEGER) { \ |
286 | 147k | if (jj < 1 || jj > nc) \ |
287 | 147k | errorcallOutOfBounds(x, 0, jj, call); \ |
288 | 147k | jj--; \ |
289 | 147k | } \ |
290 | 24.0M | for (i = 0; i < nrs; i++) { \ |
291 | 23.9M | ii = psr[i]; \ |
292 | 23.9M | if (ii != NA_INTEGER) { \ |
293 | 23.9M | if (ii < 1 || ii > nr) \ |
294 | 23.9M | errorcallOutOfBounds(x, 1, ii, call); \ |
295 | 23.9M | ii--; \ |
296 | 23.9M | } \ |
297 | 23.9M | ij = i + j * nrs; \ |
298 | 23.9M | if (ii == NA_INTEGER || jj == NA_INTEGER) \ |
299 | 23.9M | NACODE; \ |
300 | 23.9M | else { \ |
301 | 23.9M | iijj = ii + jj * nr; \ |
302 | 23.9M | STDCODE; \ |
303 | 23.9M | } \ |
304 | 23.9M | } \ |
305 | 147k | } \ |
306 | 145k | } while (0) |
307 | | |
308 | | static SEXP MatrixSubset(SEXP x, SEXP s, SEXP call, int drop) |
309 | 145k | { |
310 | 145k | SEXP attr, result, sr, sc, dim; |
311 | 145k | int nr, nc, nrs, ncs; |
312 | 145k | R_xlen_t i, j, ii, jj, ij, iijj; |
313 | | |
314 | 145k | nr = nrows(x); |
315 | 145k | nc = ncols(x); |
316 | | |
317 | | /* Note that "s" is protected on entry. */ |
318 | | /* The following ensures that pointers remain protected. */ |
319 | 145k | dim = getAttrib(x, R_DimSymbol); |
320 | | |
321 | 145k | sr = SETCAR (s, int_arraySubscript(0, CAR(s), dim, x, call)); |
322 | 145k | sc = SETCADR(s, int_arraySubscript(1, CADR(s), dim, x, call)); |
323 | 145k | nrs = LENGTH(sr); |
324 | 145k | ncs = LENGTH(sc); |
325 | | /* Check this does not overflow: currently only possible on 32-bit */ |
326 | 145k | if ((double)nrs * (double)ncs > R_XLEN_T_MAX) |
327 | 0 | error(_("dimensions would exceed maximum size of array")); |
328 | 145k | PROTECT(sr); |
329 | 145k | PROTECT(sc); |
330 | 145k | result = allocVector(TYPEOF(x), (R_xlen_t) nrs * (R_xlen_t) ncs); |
331 | 145k | const int *psr = INTEGER_RO(sr); |
332 | 145k | const int *psc = INTEGER_RO(sc); |
333 | 145k | PROTECT(result); |
334 | 145k | switch(TYPEOF(x)) { |
335 | 0 | case LGLSXP: |
336 | 0 | MATRIX_SUBSET_LOOP(LOGICAL0(result)[ij] = LOGICAL_ELT(x, iijj), |
337 | 0 | LOGICAL0(result)[ij] = NA_LOGICAL); |
338 | 0 | break; |
339 | 0 | case INTSXP: |
340 | 0 | MATRIX_SUBSET_LOOP(INTEGER0(result)[ij] = INTEGER_ELT(x, iijj), |
341 | 0 | INTEGER0(result)[ij] = NA_INTEGER); |
342 | 0 | break; |
343 | 0 | case REALSXP: |
344 | 0 | MATRIX_SUBSET_LOOP(REAL0(result)[ij] = REAL_ELT(x, iijj), |
345 | 0 | REAL0(result)[ij] = NA_REAL); |
346 | 0 | break; |
347 | 0 | case CPLXSXP: |
348 | 0 | { |
349 | 0 | Rcomplex NA_CPLX = { .r = NA_REAL, .i = NA_REAL }; |
350 | 0 | MATRIX_SUBSET_LOOP(COMPLEX0(result)[ij] = COMPLEX_ELT(x, iijj), |
351 | 0 | COMPLEX0(result)[ij] = NA_CPLX); |
352 | 0 | } |
353 | 0 | break; |
354 | 145k | case STRSXP: |
355 | 145k | MATRIX_SUBSET_LOOP(SET_STRING_ELT(result, ij, STRING_ELT(x, iijj)), |
356 | 145k | SET_STRING_ELT(result, ij, NA_STRING)); |
357 | 145k | break; |
358 | 0 | case VECSXP: |
359 | 0 | case EXPRSXP: |
360 | 0 | MATRIX_SUBSET_LOOP(SET_VECTOR_ELT(result, ij, |
361 | 0 | VECTOR_ELT_FIX_NAMED(x, iijj)), |
362 | 0 | SET_VECTOR_ELT(result, ij, R_NilValue)); |
363 | 0 | break; |
364 | 0 | case RAWSXP: |
365 | 0 | MATRIX_SUBSET_LOOP(RAW0(result)[ij] = RAW_ELT(x, iijj), |
366 | 0 | RAW0(result)[ij] = (Rbyte) 0); |
367 | 0 | break; |
368 | 0 | default: |
369 | 0 | errorcall(call, _("matrix subscripting not handled for this type")); |
370 | 0 | break; |
371 | 145k | } |
372 | | |
373 | 145k | if(nrs >= 0 && ncs >= 0) { |
374 | 145k | PROTECT(attr = allocVector(INTSXP, 2)); |
375 | 145k | INTEGER0(attr)[0] = nrs; |
376 | 145k | INTEGER0(attr)[1] = ncs; |
377 | 145k | if(!isNull(getAttrib(dim, R_NamesSymbol))) |
378 | 0 | setAttrib(attr, R_NamesSymbol, getAttrib(dim, R_NamesSymbol)); |
379 | 145k | setAttrib(result, R_DimSymbol, attr); |
380 | 145k | UNPROTECT(1); |
381 | 145k | } |
382 | | |
383 | | /* The matrix elements have been transferred. Now we need to */ |
384 | | /* transfer the attributes. Most importantly, we need to subset */ |
385 | | /* the dimnames of the returned value. */ |
386 | | |
387 | 145k | if (nrs >= 0 && ncs >= 0) { |
388 | 145k | SEXP dimnames, dimnamesnames, newdimnames; |
389 | 145k | dimnames = getAttrib(x, R_DimNamesSymbol); |
390 | 145k | PROTECT(dimnamesnames = getAttrib(dimnames, R_NamesSymbol)); |
391 | 145k | if (!isNull(dimnames)) { |
392 | 144k | PROTECT(newdimnames = allocVector(VECSXP, 2)); |
393 | 144k | if (TYPEOF(dimnames) == VECSXP) { |
394 | 144k | SET_VECTOR_ELT(newdimnames, 0, |
395 | 144k | ExtractSubset(VECTOR_ELT(dimnames, 0), sr, call)); |
396 | 144k | SET_VECTOR_ELT(newdimnames, 1, |
397 | 144k | ExtractSubset(VECTOR_ELT(dimnames, 1), sc, call)); |
398 | 144k | } |
399 | 0 | else { |
400 | 0 | SET_VECTOR_ELT(newdimnames, 0, |
401 | 0 | ExtractSubset(CAR(dimnames), sr, call)); |
402 | 0 | SET_VECTOR_ELT(newdimnames, 1, |
403 | 0 | ExtractSubset(CADR(dimnames), sc, call)); |
404 | 0 | } |
405 | 144k | setAttrib(newdimnames, R_NamesSymbol, dimnamesnames); |
406 | 144k | setAttrib(result, R_DimNamesSymbol, newdimnames); |
407 | 144k | UNPROTECT(1); /* newdimnames */ |
408 | 144k | } |
409 | 145k | UNPROTECT(1); /* dimnamesnames */ |
410 | 145k | } |
411 | | /* Probably should not do this: |
412 | | copyMostAttrib(x, result); */ |
413 | 145k | if (drop) |
414 | 144k | DropDims(result); |
415 | 145k | UNPROTECT(3); |
416 | 145k | return result; |
417 | 145k | } |
418 | | |
419 | | static R_INLINE R_xlen_t findASubIndex(R_xlen_t k, const int * const *subs, |
420 | | const int *indx, const int *pxdims, |
421 | | const R_xlen_t *offset, |
422 | | SEXP call) |
423 | 0 | { |
424 | 0 | R_xlen_t ii = 0; |
425 | 0 | for (int j = 0; j < k; j++) { |
426 | 0 | int jj = subs[j][indx[j]]; |
427 | 0 | if (jj == NA_INTEGER) |
428 | 0 | return NA_INTEGER; |
429 | 0 | ii += (jj - 1) * offset[j]; |
430 | 0 | } |
431 | 0 | return ii; |
432 | 0 | } |
433 | | |
434 | 0 | #define ARRAY_SUBSET_LOOP(STDCODE, NACODE) do { \ |
435 | 0 | for (R_xlen_t i = 0; i < n; i++) { \ |
436 | 0 | R_xlen_t ii = findASubIndex(k, subs, indx, \ |
437 | 0 | pxdims, offset, call); \ |
438 | 0 | if (ii != NA_INTEGER) \ |
439 | 0 | STDCODE; \ |
440 | 0 | else \ |
441 | 0 | NACODE; \ |
442 | 0 | if (n > 1) { \ |
443 | 0 | int j = 0; \ |
444 | 0 | while (++indx[j] >= bound[j]) { \ |
445 | 0 | indx[j] = 0; \ |
446 | 0 | j = (j + 1) % k; \ |
447 | 0 | } \ |
448 | 0 | } \ |
449 | 0 | } \ |
450 | 0 | } while (0) |
451 | | |
452 | | static SEXP ArraySubset(SEXP x, SEXP s, SEXP call, int drop) |
453 | 0 | { |
454 | 0 | int k, mode; |
455 | 0 | SEXP dimnames, dimnamesnames, p, q, r, result, xdims; |
456 | 0 | const void *vmaxsave = vmaxget(); |
457 | |
|
458 | 0 | mode = TYPEOF(x); |
459 | 0 | xdims = getAttrib(x, R_DimSymbol); |
460 | 0 | k = length(xdims); |
461 | 0 | const int *pxdims = INTEGER_RO(xdims); |
462 | | |
463 | | /* k is now the number of dims */ |
464 | 0 | const int **subs = (const int**)R_alloc(k, sizeof(int*)); |
465 | 0 | int *indx = (int*)R_alloc(k, sizeof(int)); |
466 | 0 | int *bound = (int*)R_alloc(k, sizeof(int)); |
467 | 0 | R_xlen_t *offset = (R_xlen_t*)R_alloc(k, sizeof(R_xlen_t)); |
468 | | |
469 | | /* Construct a vector to contain the returned values. */ |
470 | | /* Store its extents. */ |
471 | |
|
472 | 0 | R_xlen_t n = 1; |
473 | 0 | r = s; |
474 | 0 | for (int i = 0; i < k; i++) { |
475 | 0 | SETCAR(r, int_arraySubscript(i, CAR(r), xdims, x, call)); |
476 | 0 | bound[i] = LENGTH(CAR(r)); |
477 | 0 | n *= bound[i]; |
478 | 0 | r = CDR(r); |
479 | 0 | } |
480 | |
|
481 | 0 | r = s; |
482 | 0 | for (int i = 0; i < k; i++) { |
483 | 0 | indx[i] = 0; |
484 | 0 | subs[i] = INTEGER_RO(CAR(r)); |
485 | 0 | r = CDR(r); |
486 | 0 | } |
487 | 0 | offset[0] = 1; |
488 | 0 | for (int i = 1; i < k; i++) |
489 | 0 | offset[i] = offset[i - 1] * pxdims[i - 1]; |
490 | | |
491 | | /* range check on indices -- the lower bound check may not be needed */ |
492 | 0 | for (int i = 0; i < k; i++) |
493 | 0 | for (int j = 0; j < bound[i]; j++) { |
494 | 0 | int jj = subs[i][j]; |
495 | 0 | if (jj > pxdims[i] || |
496 | | /* this should not be needed as indices reaching this |
497 | | point should be positive or NA_INTEGER, which is |
498 | | negative */ |
499 | 0 | (jj < 1 && jj != NA_INTEGER)) |
500 | 0 | errorcallOutOfBounds(x, i, jj, call); |
501 | 0 | } |
502 | | |
503 | | /* Transfer the subset elements from "x" to "a". */ |
504 | 0 | PROTECT(result = allocVector(mode, n)); |
505 | 0 | switch (mode) { |
506 | 0 | case LGLSXP: |
507 | 0 | ARRAY_SUBSET_LOOP(LOGICAL0(result)[i] = LOGICAL_ELT(x, ii), |
508 | 0 | LOGICAL0(result)[i] = NA_LOGICAL); |
509 | 0 | break; |
510 | 0 | case INTSXP: |
511 | 0 | ARRAY_SUBSET_LOOP(INTEGER0(result)[i] = INTEGER_ELT(x, ii), |
512 | 0 | INTEGER0(result)[i] = NA_INTEGER); |
513 | 0 | break; |
514 | 0 | case REALSXP: |
515 | 0 | ARRAY_SUBSET_LOOP(REAL0(result)[i] = REAL_ELT(x, ii), |
516 | 0 | REAL0(result)[i] = NA_REAL); |
517 | 0 | break; |
518 | 0 | case CPLXSXP: |
519 | 0 | { |
520 | 0 | Rcomplex NA_CPLX = { .r = NA_REAL, .i = NA_REAL }; |
521 | 0 | ARRAY_SUBSET_LOOP(COMPLEX0(result)[i] = COMPLEX_ELT(x, ii), |
522 | 0 | COMPLEX0(result)[i] = NA_CPLX); |
523 | 0 | } |
524 | 0 | break; |
525 | 0 | case STRSXP: |
526 | 0 | ARRAY_SUBSET_LOOP(SET_STRING_ELT(result, i, STRING_ELT(x, ii)), |
527 | 0 | SET_STRING_ELT(result, i, NA_STRING)); |
528 | 0 | break; |
529 | 0 | case VECSXP: |
530 | 0 | case EXPRSXP: |
531 | 0 | ARRAY_SUBSET_LOOP(SET_VECTOR_ELT(result, i, |
532 | 0 | VECTOR_ELT_FIX_NAMED(x, ii)), |
533 | 0 | SET_VECTOR_ELT(result, i, R_NilValue)); |
534 | 0 | break; |
535 | 0 | case RAWSXP: |
536 | 0 | ARRAY_SUBSET_LOOP(RAW0(result)[i] = RAW_ELT(x, ii), |
537 | 0 | RAW0(result)[i] = (Rbyte) 0); |
538 | 0 | break; |
539 | 0 | default: |
540 | 0 | errorcall(call, _("array subscripting not handled for this type")); |
541 | 0 | break; |
542 | 0 | } |
543 | | |
544 | 0 | SEXP new_dim = PROTECT(allocVector(INTSXP, k)); |
545 | 0 | for(int i = 0 ; i < k ; i++) |
546 | 0 | INTEGER0(new_dim)[i] = bound[i]; |
547 | 0 | if(!isNull(getAttrib(xdims, R_NamesSymbol))) |
548 | 0 | setAttrib(new_dim, R_NamesSymbol, getAttrib(xdims, R_NamesSymbol)); |
549 | 0 | setAttrib(result, R_DimSymbol, new_dim); |
550 | 0 | UNPROTECT(1); // new_dim |
551 | | |
552 | | /* The array elements have been transferred. */ |
553 | | /* Now we need to transfer the attributes. */ |
554 | | /* Most importantly, we need to subset the */ |
555 | | /* dimnames of the returned value. */ |
556 | |
|
557 | 0 | dimnames = getAttrib(x, R_DimNamesSymbol); |
558 | 0 | PROTECT(dimnamesnames = getAttrib(dimnames, R_NamesSymbol)); |
559 | 0 | if (dimnames != R_NilValue) { |
560 | 0 | int j = 0; |
561 | 0 | PROTECT(xdims = allocVector(VECSXP, k)); |
562 | 0 | if (TYPEOF(dimnames) == VECSXP) { |
563 | 0 | r = s; |
564 | 0 | for (int i = 0; i < k ; i++) { |
565 | 0 | if (bound[i] > 0) { |
566 | 0 | SET_VECTOR_ELT(xdims, j++, |
567 | 0 | ExtractSubset(VECTOR_ELT(dimnames, i), CAR(r), call)); |
568 | 0 | } else { /* 0-length dims have NULL dimnames */ |
569 | 0 | SET_VECTOR_ELT(xdims, j++, R_NilValue); |
570 | 0 | } |
571 | 0 | r = CDR(r); |
572 | 0 | } |
573 | 0 | } |
574 | 0 | else { |
575 | 0 | p = dimnames; |
576 | 0 | q = xdims; |
577 | 0 | r = s; |
578 | 0 | for(int i = 0 ; i < k; i++) { |
579 | 0 | SETCAR(q, ExtractSubset(CAR(p), CAR(r), call)); |
580 | 0 | p = CDR(p); |
581 | 0 | q = CDR(q); |
582 | 0 | r = CDR(r); |
583 | 0 | } |
584 | 0 | } |
585 | 0 | setAttrib(xdims, R_NamesSymbol, dimnamesnames); |
586 | 0 | setAttrib(result, R_DimNamesSymbol, xdims); |
587 | 0 | UNPROTECT(1); /* xdims */ |
588 | 0 | } |
589 | | /* This was removed for matrices in 1998 |
590 | | copyMostAttrib(x, result); */ |
591 | | /* Free temporary memory */ |
592 | 0 | vmaxset(vmaxsave); |
593 | 0 | if (drop) |
594 | 0 | DropDims(result); |
595 | 0 | UNPROTECT(2); /* dimnamesnames, result */ |
596 | 0 | return result; |
597 | 0 | } |
598 | | |
599 | | |
600 | | /* Returns and removes a named argument from argument list args. |
601 | | The search ends as soon as a matching argument is found. If |
602 | | the argument is not found, the argument list is not modified |
603 | | and R_NilValue is returned. |
604 | | */ |
605 | | static SEXP ExtractArg(SEXP args, SEXP arg_sym) |
606 | 42.5M | { |
607 | 42.5M | SEXP arg, prev_arg; |
608 | 42.5M | int found = 0; |
609 | | |
610 | 132M | for (arg = prev_arg = args; arg != R_NilValue; arg = CDR(arg)) { |
611 | 94.4M | if(TAG(arg) == arg_sym) { |
612 | 4.63M | if (arg == prev_arg) /* found at head of args */ |
613 | 0 | args = CDR(args); |
614 | 4.63M | else |
615 | 4.63M | SETCDR(prev_arg, CDR(arg)); |
616 | 4.63M | found = 1; |
617 | 4.63M | break; |
618 | 4.63M | } |
619 | 89.8M | else prev_arg = arg; |
620 | 94.4M | } |
621 | 42.5M | return found ? CAR(arg) : R_NilValue; |
622 | 42.5M | } |
623 | | |
624 | | /* Extracts the drop argument, if present, from the argument list. |
625 | | The object being subsetted must be the first argument. */ |
626 | | static void ExtractDropArg(SEXP el, int *drop) |
627 | 28.3M | { |
628 | 28.3M | *drop = asLogical(ExtractArg(el, R_DropSymbol)); |
629 | 28.3M | if (*drop == NA_LOGICAL) *drop = 1; |
630 | 28.3M | } |
631 | | |
632 | | |
633 | | /* Extracts and, if present, removes the 'exact' argument from the |
634 | | argument list. An integer code giving the desired exact matching |
635 | | behavior is returned: |
636 | | 0 not exact |
637 | | 1 exact |
638 | | -1 not exact, but warn when partial matching is used |
639 | | */ |
640 | | static int ExtractExactArg(SEXP args) |
641 | 14.1M | { |
642 | 14.1M | SEXP argval = ExtractArg(args, R_ExactSymbol); |
643 | 14.1M | if(isNull(argval)) return 1; /* Default is true as from R 2.7.0 */ |
644 | 4.63M | int exact = asLogical(argval); |
645 | 4.63M | if (exact == NA_LOGICAL) exact = -1; |
646 | 4.63M | return exact; |
647 | 14.1M | } |
648 | | |
649 | | /* Version of DispatchOrEval for "[" and friends that speeds up simple cases. |
650 | | Also defined in subassign.c */ |
651 | | static R_INLINE |
652 | | int R_DispatchOrEvalSP(SEXP call, SEXP op, const char *generic, SEXP args, |
653 | | SEXP rho, SEXP *ans) |
654 | 9.64M | { |
655 | 9.64M | SEXP prom = NULL; |
656 | 9.64M | if (args != R_NilValue && CAR(args) != R_DotsSymbol) { |
657 | 9.64M | SEXP x = eval(CAR(args), rho); |
658 | 9.64M | PROTECT(x); |
659 | 9.64M | INCREMENT_LINKS(x); |
660 | 9.64M | if (! OBJECT(x)) { |
661 | 9.62M | *ans = CONS_NR(x, evalListKeepMissing(CDR(args), rho)); |
662 | 9.62M | DECREMENT_LINKS(x); |
663 | 9.62M | UNPROTECT(1); |
664 | 9.62M | return FALSE; |
665 | 9.62M | } |
666 | 24.5k | prom = R_mkEVPROMISE_NR(CAR(args), x); |
667 | 24.5k | args = CONS(prom, CDR(args)); |
668 | 24.5k | UNPROTECT(1); |
669 | 24.5k | } |
670 | 24.5k | PROTECT(args); |
671 | 24.5k | int disp = DispatchOrEval(call, op, generic, args, rho, ans, 0, 0); |
672 | 24.5k | if (prom) DECREMENT_LINKS(PRVALUE(prom)); |
673 | 24.5k | UNPROTECT(1); |
674 | 24.5k | return disp; |
675 | 9.64M | } |
676 | | |
677 | | /* The "[" subset operator. |
678 | | * This provides the most general form of subsetting. */ |
679 | | |
680 | | attribute_hidden SEXP do_subset(SEXP call, SEXP op, SEXP args, SEXP rho) |
681 | 885k | { |
682 | 885k | SEXP ans; |
683 | | |
684 | | /* If the first argument is an object and there is an */ |
685 | | /* appropriate method, we dispatch to that method, */ |
686 | | /* otherwise we evaluate the arguments and fall through */ |
687 | | /* to the generic code below. Note that evaluation */ |
688 | | /* retains any missing argument indicators. */ |
689 | | |
690 | | /* DispatchOrEval internal generic: [ */ |
691 | 885k | if(R_DispatchOrEvalSP(call, op, "[", args, rho, &ans)) { |
692 | | /* if(DispatchAnyOrEval(call, op, "[", args, rho, &ans, 0, 0)) */ |
693 | 264 | if (NAMED(ans)) |
694 | 0 | ENSURE_NAMEDMAX(ans); |
695 | 264 | return(ans); |
696 | 264 | } |
697 | | |
698 | | /* Method dispatch has failed, we now */ |
699 | | /* run the generic internal code. */ |
700 | 885k | return do_subset_dflt(call, op, ans, rho); |
701 | 885k | } |
702 | | |
703 | | static R_INLINE R_xlen_t scalarIndex(SEXP s) |
704 | 11.6M | { |
705 | 11.6M | if (ATTRIB(s) == R_NilValue) { |
706 | 11.5M | if (IS_SCALAR(s, INTSXP)) { |
707 | 6.71M | int ival = SCALAR_IVAL(s); |
708 | 6.71M | if (ival != NA_INTEGER) |
709 | 6.71M | return ival; |
710 | 3 | else return -1; |
711 | 6.71M | } |
712 | 4.84M | else if (IS_SCALAR(s, REALSXP)) { |
713 | 3.90M | double rval = SCALAR_DVAL(s); |
714 | | // treat infinite indices as NA, like asInteger |
715 | 3.90M | if (R_FINITE(rval)) |
716 | 3.89M | return (R_xlen_t) rval; |
717 | 4.39k | else return -1; |
718 | 3.90M | } |
719 | 937k | else return -1; |
720 | 11.5M | } |
721 | 61.3k | else return -1; |
722 | 11.6M | } |
723 | | |
724 | | // called from (R `[` => ) do_subset, but also from R .subset() : |
725 | | attribute_hidden SEXP do_subset_dflt(SEXP call, SEXP op, SEXP args, SEXP rho) |
726 | 14.2M | { |
727 | | /* By default we drop extents of length 1 */ |
728 | | |
729 | | /* Handle cases of extracting a single element from a simple vector |
730 | | or matrix directly to improve speed for these simple cases. */ |
731 | 14.2M | SEXP x = CAR(args); |
732 | 14.2M | SEXP cdrArgs = CDR(args); |
733 | 14.2M | SEXP cddrArgs = CDR(cdrArgs); |
734 | 14.2M | if (cdrArgs != R_NilValue && cddrArgs == R_NilValue && |
735 | 14.1M | TAG(cdrArgs) == R_NilValue) { |
736 | | /* one index, not named */ |
737 | 14.1M | if (ATTRIB(x) == R_NilValue) { |
738 | 11.6M | SEXP s = CAR(cdrArgs); |
739 | 11.6M | R_xlen_t i = scalarIndex(s); |
740 | 11.6M | switch (TYPEOF(x)) { |
741 | 3.00M | case REALSXP: |
742 | 3.00M | if (i >= 1 && i <= XLENGTH(x)) |
743 | 4.16k | return ScalarReal( REAL_ELT(x, i-1) ); |
744 | 3.00M | break; |
745 | 3.00M | case INTSXP: |
746 | 480k | if (i >= 1 && i <= XLENGTH(x)) |
747 | 865 | return ScalarInteger( INTEGER_ELT(x, i-1) ); |
748 | 479k | break; |
749 | 479k | case LGLSXP: |
750 | 63.1k | if (i >= 1 && i <= XLENGTH(x)) |
751 | 263 | return ScalarLogical( LOGICAL_ELT(x, i-1) ); |
752 | 62.8k | break; |
753 | | // do the more rare cases as well, since we've already prepared everything: |
754 | 62.8k | case CPLXSXP: |
755 | 2.32k | if (i >= 1 && i <= XLENGTH(x)) |
756 | 956 | return ScalarComplex( COMPLEX_ELT(x, i-1) ); |
757 | 1.36k | break; |
758 | 1.36k | case RAWSXP: |
759 | 149 | if (i >= 1 && i <= XLENGTH(x)) |
760 | 91 | return ScalarRaw( RAW_ELT(x, i-1) ); |
761 | 58 | break; |
762 | 8.06M | default: break; |
763 | 11.6M | } |
764 | 11.6M | } |
765 | 14.1M | } |
766 | 145k | else if (cddrArgs != R_NilValue && CDR(cddrArgs) == R_NilValue && |
767 | 144k | TAG(cdrArgs) == R_NilValue && TAG(cddrArgs) == R_NilValue) { |
768 | | /* two indices, not named */ |
769 | 144k | SEXP attr = ATTRIB(x); |
770 | 144k | if (TAG(attr) == R_DimSymbol && CDR(attr) == R_NilValue) { |
771 | | /* only attribute of x is 'dim' */ |
772 | 758 | SEXP dim = CAR(attr); |
773 | 758 | if (TYPEOF(dim) == INTSXP && LENGTH(dim) == 2) { |
774 | | /* x is a matrix */ |
775 | 758 | SEXP si = CAR(cdrArgs); |
776 | 758 | SEXP sj = CAR(cddrArgs); |
777 | 758 | R_xlen_t i = scalarIndex(si); |
778 | 758 | R_xlen_t j = scalarIndex(sj); |
779 | 758 | int nrow = INTEGER_ELT(dim, 0); |
780 | 758 | int ncol = INTEGER_ELT(dim, 1); |
781 | 758 | if (i > 0 && j > 0 && i <= nrow && j <= ncol) { |
782 | | /* indices are legal scalars */ |
783 | 0 | R_xlen_t k = i - 1 + nrow * (j - 1); |
784 | 0 | switch (TYPEOF(x)) { |
785 | 0 | case REALSXP: |
786 | 0 | if (k < XLENGTH(x)) |
787 | 0 | return ScalarReal( REAL_ELT(x, k) ); |
788 | 0 | break; |
789 | 0 | case INTSXP: |
790 | 0 | if (k < XLENGTH(x)) |
791 | 0 | return ScalarInteger( INTEGER_ELT(x, k) ); |
792 | 0 | break; |
793 | 0 | case LGLSXP: |
794 | 0 | if (k < XLENGTH(x)) |
795 | 0 | return ScalarLogical( LOGICAL_ELT(x, k) ); |
796 | 0 | break; |
797 | 0 | case CPLXSXP: |
798 | 0 | if (k < XLENGTH(x)) |
799 | 0 | return ScalarComplex( COMPLEX_ELT(x, k) ); |
800 | 0 | break; |
801 | 0 | case RAWSXP: |
802 | 0 | if (k < XLENGTH(x)) |
803 | 0 | return ScalarRaw( RAW_ELT(x, k) ); |
804 | 0 | break; |
805 | 0 | default: break; |
806 | 0 | } |
807 | 0 | } |
808 | 758 | } |
809 | 758 | } |
810 | 144k | } |
811 | | |
812 | 14.2M | PROTECT(args); |
813 | | |
814 | 14.2M | int drop = 1; |
815 | 14.2M | ExtractDropArg(args, &drop); |
816 | | |
817 | | /* This was intended for compatibility with S, */ |
818 | | /* but in fact S does not do this. */ |
819 | | /* FIXME: replace the test by isNull ... ? */ |
820 | | |
821 | 14.2M | if (x == R_NilValue) { |
822 | 1.63k | UNPROTECT(1); |
823 | 1.63k | return x; |
824 | 1.63k | } |
825 | | |
826 | 14.2M | SEXP subs = CDR(args); |
827 | 14.2M | int nsubs = length(subs); /* Will be short */ |
828 | 14.2M | int type = TYPEOF(x); |
829 | | |
830 | | /* Here coerce pair-based objects into generic vectors. */ |
831 | | /* All subsetting takes place on the generic vector form. */ |
832 | | |
833 | 14.2M | SEXP ax = x; |
834 | 14.2M | if (isVector(x)) |
835 | 13.6M | PROTECT(ax); |
836 | 599k | else if (type == LISTSXP || type == LANGSXP) { // *not* <DOTSXP>[] : |
837 | 599k | SEXP dim = getAttrib(x, R_DimSymbol); |
838 | 599k | int ndim = length(dim); |
839 | 599k | if (ndim > 1) { |
840 | 0 | PROTECT(ax = allocArray(VECSXP, dim)); |
841 | 0 | setAttrib(ax, R_DimNamesSymbol, getAttrib(x, R_DimNamesSymbol)); |
842 | 0 | setAttrib(ax, R_NamesSymbol, getAttrib(x, R_DimNamesSymbol)); |
843 | 0 | } |
844 | 599k | else { |
845 | 599k | PROTECT(ax = allocVector(VECSXP, length(x))); |
846 | 599k | setAttrib(ax, R_NamesSymbol, getAttrib(x, R_NamesSymbol)); |
847 | 599k | } |
848 | 599k | SEXP px; int i; |
849 | 2.09M | for(px = x, i = 0 ; px != R_NilValue ; px = CDR(px)) |
850 | 1.49M | SET_VECTOR_ELT(ax, i++, CAR(px)); |
851 | 599k | } |
852 | 2 | else errorcallNotSubsettable(x, call); |
853 | | |
854 | | /* This is the actual subsetting code. */ |
855 | | /* The separation of arrays and matrices is purely an optimization. */ |
856 | | |
857 | 14.2M | SEXP ans; |
858 | 14.2M | if(nsubs < 2) { |
859 | 14.1M | SEXP dim = getAttrib(x, R_DimSymbol); |
860 | 14.1M | int ndim = length(dim); |
861 | 14.1M | PROTECT(ans = VectorSubset(ax, (nsubs == 1 ? CAR(subs) : R_MissingArg), |
862 | 14.1M | call)); |
863 | | /* one-dimensional arrays went through here, and they should |
864 | | have their dimensions dropped only if the result has |
865 | | length one and drop == TRUE |
866 | | */ |
867 | 14.1M | if(ndim == 1) { |
868 | 0 | int len = length(ans); |
869 | 0 | if(!drop || len > 1) { |
870 | | // must grab these before the dim is set. |
871 | 0 | SEXP nm = PROTECT(getAttrib(ans, R_NamesSymbol)); |
872 | 0 | SEXP attr = PROTECT(ScalarInteger(length(ans))); |
873 | 0 | if(!isNull(getAttrib(dim, R_NamesSymbol))) |
874 | 0 | setAttrib(attr, R_NamesSymbol, getAttrib(dim, R_NamesSymbol)); |
875 | 0 | setAttrib(ans, R_DimSymbol, attr); |
876 | 0 | SEXP attrib; |
877 | 0 | if((attrib = getAttrib(x, R_DimNamesSymbol)) != R_NilValue) { |
878 | | /* reinstate dimnames, include names of dimnames */ |
879 | 0 | SEXP nattrib = PROTECT(duplicate(attrib)); |
880 | 0 | SET_VECTOR_ELT(nattrib, 0, nm); |
881 | 0 | setAttrib(ans, R_DimNamesSymbol, nattrib); |
882 | 0 | setAttrib(ans, R_NamesSymbol, R_NilValue); |
883 | 0 | UNPROTECT(1); |
884 | 0 | } |
885 | 0 | UNPROTECT(2); |
886 | 0 | } |
887 | 0 | } |
888 | 14.1M | } else { |
889 | 145k | if (nsubs != length(getAttrib(x, R_DimSymbol))) |
890 | 15 | errorcall(call, _("incorrect number of dimensions")); |
891 | 145k | if (nsubs == 2) |
892 | 145k | ans = MatrixSubset(ax, subs, call, drop); |
893 | 17 | else |
894 | 17 | ans = ArraySubset(ax, subs, call, drop); |
895 | 145k | PROTECT(ans); |
896 | 145k | } |
897 | | |
898 | | /* Note: we do not coerce back to pair-based lists. */ |
899 | | /* They are "defunct" in this version of R. */ |
900 | | |
901 | 14.2M | if (type == LANGSXP) { |
902 | 599k | ax = ans; |
903 | 599k | PROTECT(ans = allocLang(LENGTH(ax))); |
904 | 599k | if ( LENGTH(ax) > 0 ) { |
905 | 595k | SEXP px; int i; |
906 | 1.47M | for(px = ans, i = 0 ; px != R_NilValue ; px = CDR(px)) |
907 | 882k | SETCAR(px, VECTOR_ELT(ax, i++)); |
908 | 595k | setAttrib(ans, R_DimSymbol, getAttrib(ax, R_DimSymbol)); |
909 | 595k | setAttrib(ans, R_DimNamesSymbol, getAttrib(ax, R_DimNamesSymbol)); |
910 | 595k | setAttrib(ans, R_NamesSymbol, getAttrib(ax, R_NamesSymbol)); |
911 | 595k | RAISE_NAMED(ans, NAMED(ax)); /* PR#7924 */ |
912 | 595k | } |
913 | 599k | } |
914 | 13.6M | else { |
915 | 13.6M | PROTECT(ans); |
916 | 13.6M | } |
917 | 14.2M | if (ATTRIB(ans) != R_NilValue) { /* remove probably erroneous attr's */ |
918 | 168k | setAttrib(ans, R_TspSymbol, R_NilValue); |
919 | | #ifdef _S4_subsettable |
920 | | if(!IS_S4_OBJECT(x)) |
921 | | #endif |
922 | 168k | setAttrib(ans, R_ClassSymbol, R_NilValue); |
923 | 168k | } |
924 | 14.2M | UNPROTECT(4); |
925 | 14.2M | return ans; |
926 | 14.2M | } |
927 | | |
928 | | |
929 | | /* The [[ subset operator. It needs to be fast. */ |
930 | | /* The arguments to this call are evaluated on entry. */ |
931 | | |
932 | | attribute_hidden SEXP do_subset2(SEXP call, SEXP op, SEXP args, SEXP rho) |
933 | 7.85M | { |
934 | 7.85M | SEXP ans; |
935 | | |
936 | | /* If the first argument is an object and there is */ |
937 | | /* an appropriate method, we dispatch to that method, */ |
938 | | /* otherwise we evaluate the arguments and fall */ |
939 | | /* through to the generic code below. Note that */ |
940 | | /* evaluation retains any missing argument indicators. */ |
941 | | |
942 | | /* DispatchOrEval internal generic: [[ */ |
943 | 7.85M | if(R_DispatchOrEvalSP(call, op, "[[", args, rho, &ans)) { |
944 | 0 | if (NAMED(ans)) |
945 | 0 | ENSURE_NAMEDMAX(ans); |
946 | 0 | return(ans); |
947 | 0 | } |
948 | | |
949 | | /* Method dispatch has failed. */ |
950 | | /* We now run the generic internal code. */ |
951 | | |
952 | 7.85M | return do_subset2_dflt(call, op, ans, rho); |
953 | 7.85M | } |
954 | | |
955 | | attribute_hidden SEXP do_subset2_dflt(SEXP call, SEXP op, SEXP args, SEXP rho) |
956 | 14.1M | { |
957 | 14.1M | SEXP ans, dims, dimnames, indx, subs, x; |
958 | 14.1M | int i, ndims, nsubs; |
959 | 14.1M | int drop = 1; |
960 | 14.1M | R_xlen_t offset = 0; |
961 | | |
962 | 14.1M | PROTECT(args); |
963 | 14.1M | ExtractDropArg(args, &drop); |
964 | | /* Is partial matching ok? When the exact arg is NA, a warning is |
965 | | issued if partial matching occurs. |
966 | | */ |
967 | 14.1M | int exact = ExtractExactArg(args); |
968 | 14.1M | int pok = (exact == -1) ? exact : ! exact; |
969 | | |
970 | 14.1M | x = CAR(args); |
971 | | |
972 | | /* Get the subscripting and dimensioning information */ |
973 | | /* and check that any array subscripting is compatible. */ |
974 | | |
975 | 14.1M | subs = CDR(args); |
976 | 14.1M | if(0 == (nsubs = length(subs))) |
977 | 1 | errorcall(call, _("no index specified")); |
978 | | |
979 | | /* This code was intended for compatibility with S, */ |
980 | | /* but in fact S does not do this. Will anyone notice? */ |
981 | 14.1M | if (x == R_NilValue) { |
982 | 51.1k | UNPROTECT(1); /* args */ |
983 | 51.1k | if(CAR(subs) == R_MissingArg) |
984 | 1 | errorcallMissingSubs(x, call); |
985 | | // else |
986 | 51.1k | return x; |
987 | 51.1k | } |
988 | | |
989 | 14.0M | dims = getAttrib(x, R_DimSymbol); |
990 | 14.0M | ndims = length(dims); |
991 | 14.0M | if(nsubs > 1 && nsubs != ndims) |
992 | 5 | errorcall(call, _("incorrect number of subscripts")); |
993 | | |
994 | | /* code to allow classes to extend environment */ |
995 | 14.0M | if(TYPEOF(x) == OBJSXP) { |
996 | 0 | SEXP xs = x; |
997 | 0 | x = R_getS4DataSlot(x, ANYSXP); |
998 | 0 | if(x == R_NilValue) |
999 | 0 | errorcall(call, _("this %s class is not subsettable"), |
1000 | 0 | IS_S4_OBJECT(xs) ? "S4" : "object"); |
1001 | 0 | } |
1002 | 14.0M | PROTECT(x); |
1003 | | |
1004 | | /* split out ENVSXP for now */ |
1005 | 14.0M | if( TYPEOF(x) == ENVSXP ) { |
1006 | 58.3k | if( nsubs != 1 || !isString(CAR(subs)) || length(CAR(subs)) != 1 ) |
1007 | 0 | errorcall(call, _("wrong arguments for subsetting an environment")); |
1008 | 58.3k | ans = R_findVarInFrame(x, installTrChar(STRING_ELT(CAR(subs), 0))); |
1009 | 58.3k | if( TYPEOF(ans) == PROMSXP ) { |
1010 | 9.22k | PROTECT(ans); |
1011 | 9.22k | ans = eval(ans, R_GlobalEnv); |
1012 | 9.22k | UNPROTECT(1); /* ans */ |
1013 | 49.1k | } else ENSURE_NAMEDMAX(ans); |
1014 | | |
1015 | 58.3k | UNPROTECT(2); /* args, x */ |
1016 | 58.3k | if(ans == R_UnboundValue) |
1017 | 17.8k | return(R_NilValue); |
1018 | 40.5k | if (NAMED(ans)) |
1019 | 40.5k | ENSURE_NAMEDMAX(ans); |
1020 | 40.5k | return ans; |
1021 | 58.3k | } |
1022 | | |
1023 | | /* back to the regular program */ |
1024 | 14.0M | if (!(isVector(x) || isList(x) || isLanguage(x))) |
1025 | 1 | errorcallNotSubsettable(x, call); |
1026 | | |
1027 | | #ifndef SWITCH_TO_REFCNT |
1028 | | int named_x; |
1029 | | named_x = NAMED(x); /* x may change below; save this now. See PR#13411 */ |
1030 | | #endif |
1031 | | |
1032 | 14.0M | if(nsubs == 1) { /* vector indexing */ |
1033 | 14.0M | SEXP thesub = CAR(subs); |
1034 | 14.0M | int len = length(thesub); |
1035 | | |
1036 | 14.0M | if (len > 1) { |
1037 | 11 | #ifdef SWITCH_TO_REFCNT |
1038 | 11 | if (IS_GETTER_CALL(call)) { |
1039 | | /* This is (most likely) a getter call in a complex |
1040 | | assighment so we duplicate as needed. The original |
1041 | | x should have been duplicated if it might be |
1042 | | shared, but might get additional references before |
1043 | | it arrives here. */ |
1044 | 5 | if (MAYBE_SHARED(x)) { |
1045 | 2 | x = shallow_duplicate(x); |
1046 | 2 | UNPROTECT(1); /* old x */ |
1047 | 2 | PROTECT(x); |
1048 | 2 | } |
1049 | 5 | x = vectorIndex(x, thesub, 0, len-1, pok, call, TRUE); |
1050 | 5 | } |
1051 | 6 | else |
1052 | 6 | x = vectorIndex(x, thesub, 0, len-1, pok, call, FALSE); |
1053 | | #else |
1054 | | x = vectorIndex(x, thesub, 0, len-1, pok, call, FALSE); |
1055 | | named_x = NAMED(x); |
1056 | | #endif |
1057 | 11 | UNPROTECT(1); /* x */ |
1058 | 11 | PROTECT(x); |
1059 | 11 | } |
1060 | | |
1061 | 14.0M | SEXP xnames = PROTECT(getAttrib(x, R_NamesSymbol)); |
1062 | 14.0M | offset = get1index(thesub, xnames, |
1063 | 14.0M | xlength(x), pok, len > 1 ? len-1 : -1, call); |
1064 | 14.0M | UNPROTECT(1); /* xnames */ |
1065 | 14.0M | if (offset < 0 || offset >= xlength(x)) { |
1066 | | /* a bold attempt to get the same behaviour for $ and [[ */ |
1067 | 50.3k | if (offset < 0 && (isNewList(x) || |
1068 | 2 | isExpression(x) || |
1069 | 2 | isList(x) || |
1070 | 50.3k | isLanguage(x))) { |
1071 | 50.3k | UNPROTECT(2); /* args, x */ |
1072 | 50.3k | return R_NilValue; |
1073 | 50.3k | } |
1074 | 17 | else errorcallOutOfBoundsSEXP(x, -1, thesub, call); |
1075 | 50.3k | } |
1076 | 14.0M | } else { /* nsubs == ndims >= 2 : matrix|array indexing */ |
1077 | | /* Here we use the fact that: */ |
1078 | | /* CAR(R_NilValue) = R_NilValue */ |
1079 | | /* CDR(R_NilValue) = R_NilValue */ |
1080 | | |
1081 | 7 | int ndn; /* Number of dimnames. Unlikely to be anything but |
1082 | | 0 or nsubs, but just in case... */ |
1083 | | |
1084 | 7 | PROTECT(indx = allocVector(INTSXP, nsubs)); |
1085 | 7 | int *pindx = INTEGER(indx); |
1086 | 7 | const int *pdims = INTEGER_RO(dims); |
1087 | 7 | dimnames = getAttrib(x, R_DimNamesSymbol); |
1088 | 7 | ndn = length(dimnames); |
1089 | 7 | for (i = 0; i < nsubs; i++) { |
1090 | 0 | SEXP thesub = CAR(subs); |
1091 | 0 | pindx[i] = (int) |
1092 | 0 | get1index(thesub, |
1093 | 0 | (i < ndn) ? VECTOR_ELT(dimnames, i) : R_NilValue, |
1094 | 0 | pdims[i], pok, -1, call); |
1095 | 0 | subs = CDR(subs); |
1096 | 0 | if (pindx[i] < 0 || pindx[i] >= pdims[i]) |
1097 | 0 | errorcallOutOfBoundsSEXP(x, i, thesub, call); |
1098 | 0 | } |
1099 | 7 | offset = 0; |
1100 | 7 | for (i = (nsubs - 1); i > 0; i--) |
1101 | 0 | offset = (offset + pindx[i]) * pdims[i - 1]; |
1102 | 7 | offset += pindx[0]; |
1103 | 7 | UNPROTECT(1); /* indx */ |
1104 | 7 | } |
1105 | | |
1106 | 13.9M | if(isPairList(x)) { |
1107 | 1.42M | #ifdef LONG_VECTOR_SUPPORT |
1108 | 1.42M | if (offset > R_SHORT_LEN_MAX) |
1109 | 0 | error("invalid subscript for pairlist"); |
1110 | 1.42M | #endif |
1111 | 1.42M | ans = CAR(nthcdr(x, (int) offset)); |
1112 | | #ifndef SWITCH_TO_REFCNT |
1113 | | RAISE_NAMED(ans, named_x); |
1114 | | #endif |
1115 | 12.5M | } else if(isVectorList(x)) { |
1116 | | /* did unconditional duplication before 2.4.0 */ |
1117 | 9.38M | ans = VECTOR_ELT(x, offset); |
1118 | | #ifndef SWITCH_TO_REFCNT |
1119 | | RAISE_NAMED(ans, named_x); |
1120 | | #endif |
1121 | 9.38M | } else { |
1122 | 3.15M | ans = PROTECT(allocVector(TYPEOF(x), 1)); |
1123 | 3.15M | switch (TYPEOF(x)) { |
1124 | 0 | case LGLSXP: |
1125 | 0 | LOGICAL0(ans)[0] = LOGICAL_ELT(x, offset); |
1126 | 0 | break; |
1127 | 2.96M | case INTSXP: |
1128 | 2.96M | INTEGER0(ans)[0] = INTEGER_ELT(x, offset); |
1129 | 2.96M | break; |
1130 | 129k | case REALSXP: |
1131 | 129k | REAL0(ans)[0] = REAL_ELT(x, offset); |
1132 | 129k | break; |
1133 | 3 | case CPLXSXP: |
1134 | 3 | COMPLEX0(ans)[0] = COMPLEX_ELT(x, offset); |
1135 | 3 | break; |
1136 | 67.5k | case STRSXP: |
1137 | 67.5k | SET_STRING_ELT(ans, 0, STRING_ELT(x, offset)); |
1138 | 67.5k | break; |
1139 | 0 | case RAWSXP: |
1140 | 0 | RAW0(ans)[0] = RAW_ELT(x, offset); |
1141 | 0 | break; |
1142 | 0 | default: |
1143 | 0 | UNIMPLEMENTED_TYPE("do_subset2", x); |
1144 | 3.15M | } |
1145 | 3.15M | UNPROTECT(1); /* ans */ |
1146 | 3.15M | } |
1147 | 13.9M | UNPROTECT(2); /* args, x */ |
1148 | 13.9M | return ans; |
1149 | 13.9M | } |
1150 | | |
1151 | | attribute_hidden SEXP dispatch_subset2(SEXP x, R_xlen_t i, SEXP call, SEXP rho) |
1152 | 1.96M | { |
1153 | 1.96M | static SEXP bracket_op = NULL; |
1154 | 1.96M | SEXP args, x_elt; |
1155 | 1.96M | if (isObject(x)) { |
1156 | 0 | if (bracket_op == NULL) |
1157 | 0 | bracket_op = R_Primitive("[["); |
1158 | 0 | PROTECT(args = list2(x, ScalarReal((double)i + 1))); |
1159 | 0 | x_elt = do_subset2(call, bracket_op, args, rho); |
1160 | 0 | UNPROTECT(1); |
1161 | 1.96M | } else { |
1162 | | // FIXME: throw error if not a list |
1163 | 1.96M | x_elt = VECTOR_ELT(x, i); |
1164 | 1.96M | } |
1165 | 1.96M | return(x_elt); |
1166 | 1.96M | } |
1167 | | |
1168 | | enum pmatch { |
1169 | | NO_MATCH, |
1170 | | EXACT_MATCH, |
1171 | | PARTIAL_MATCH |
1172 | | }; |
1173 | | |
1174 | | /* A helper to partially match tags against a candidate. |
1175 | | Tags are always in the native charset. |
1176 | | */ |
1177 | | /* Returns: */ |
1178 | | static |
1179 | | enum pmatch |
1180 | | pstrmatch(SEXP target, SEXP input, size_t slen) |
1181 | 37.0M | { |
1182 | 37.0M | const char *st = ""; |
1183 | 37.0M | const char *si = ""; |
1184 | 37.0M | const void *vmax = vmaxget(); |
1185 | | |
1186 | 37.0M | if(target == R_NilValue) |
1187 | 0 | return NO_MATCH; |
1188 | | |
1189 | 37.0M | switch (TYPEOF(target)) { |
1190 | 6.09k | case SYMSXP: |
1191 | 6.09k | st = CHAR(PRINTNAME(target)); |
1192 | 6.09k | break; |
1193 | 37.0M | case CHARSXP: |
1194 | 37.0M | st = translateChar(target); |
1195 | 37.0M | break; |
1196 | 37.0M | } |
1197 | 37.0M | si = translateChar(input); |
1198 | 37.0M | if(si[0] != '\0' && strncmp(st, si, slen) == 0) { |
1199 | 6.18M | vmaxset(vmax); |
1200 | 6.18M | return (strlen(st) == slen) ? EXACT_MATCH : PARTIAL_MATCH; |
1201 | 30.8M | } else { |
1202 | 30.8M | vmaxset(vmax); |
1203 | 30.8M | return NO_MATCH; |
1204 | 30.8M | } |
1205 | 37.0M | } |
1206 | | |
1207 | | attribute_hidden SEXP |
1208 | | fixSubset3Args(SEXP call, SEXP args, SEXP env, SEXP* syminp) |
1209 | 928k | { |
1210 | 928k | SEXP input, nlist; |
1211 | | |
1212 | | /* first translate CADR of args into a string so that we can |
1213 | | pass it down to DispatchorEval and have it behave correctly */ |
1214 | | |
1215 | 928k | PROTECT(input = allocVector(STRSXP, 1)); |
1216 | 928k | nlist = CADR(args); |
1217 | 928k | if (TYPEOF(nlist) == PROMSXP) |
1218 | 38 | nlist = eval(nlist, env); |
1219 | 928k | if(isSymbol(nlist)) { |
1220 | 928k | if (syminp != NULL) |
1221 | 24.6k | *syminp = nlist; |
1222 | 928k | SET_STRING_ELT(input, 0, PRINTNAME(nlist)); |
1223 | 928k | } else if(isString(nlist) ) { |
1224 | 51 | if (LENGTH(nlist) != 1) |
1225 | 0 | error(_("invalid subscript length")); |
1226 | 51 | SET_STRING_ELT(input, 0, STRING_ELT(nlist, 0)); |
1227 | 51 | } |
1228 | 1 | else { |
1229 | 1 | errorcall(call,_("invalid subscript type '%s'"), |
1230 | 1 | R_typeToChar(nlist)); |
1231 | 1 | return R_NilValue; /*-Wall*/ |
1232 | 1 | } |
1233 | | |
1234 | | /* replace the second argument with a string */ |
1235 | | |
1236 | | /* Previously this was SETCADR(args, input); */ |
1237 | | /* which could cause problems when nlist was */ |
1238 | | /* ..., as in PR#8718 */ |
1239 | | |
1240 | 928k | args = shallow_duplicate(args); |
1241 | 928k | SETCADR(args, input); |
1242 | 928k | UNPROTECT(1); /* input */ |
1243 | 928k | return args; |
1244 | 928k | } |
1245 | | |
1246 | | /* The $ subset operator. |
1247 | | We need to be sure to only evaluate the first argument. |
1248 | | The second will be a symbol that needs to be matched, not evaluated. |
1249 | | */ |
1250 | | attribute_hidden SEXP do_subset3(SEXP call, SEXP op, SEXP args, SEXP env) |
1251 | 904k | { |
1252 | 904k | SEXP ans; |
1253 | | |
1254 | 904k | checkArity(op, args); |
1255 | 904k | PROTECT(args = fixSubset3Args(call, args, env, NULL)); |
1256 | | |
1257 | | /* If the first argument is an object and there is */ |
1258 | | /* an appropriate method, we dispatch to that method, */ |
1259 | | /* otherwise we evaluate the arguments and fall */ |
1260 | | /* through to the generic code below. Note that */ |
1261 | | /* evaluation retains any missing argument indicators. */ |
1262 | | |
1263 | | /* DispatchOrEval internal generic: $ */ |
1264 | 904k | if(R_DispatchOrEvalSP(call, op, "$", args, env, &ans)) { |
1265 | 0 | UNPROTECT(1); /* args */ |
1266 | 0 | if (NAMED(ans)) |
1267 | 0 | ENSURE_NAMEDMAX(ans); |
1268 | 0 | return(ans); |
1269 | 0 | } |
1270 | 904k | PROTECT(ans); |
1271 | 904k | ans = R_subset3_dflt(CAR(ans), STRING_ELT(CADR(args), 0), call); |
1272 | 904k | UNPROTECT(2); /* args, ans */ |
1273 | 904k | return ans; |
1274 | 904k | } |
1275 | | |
1276 | | /* also used in eval.c */ |
1277 | | attribute_hidden SEXP R_subset3_dflt(SEXP x, SEXP input, SEXP call) |
1278 | 7.49M | { |
1279 | 7.49M | SEXP y; |
1280 | 7.49M | PROTECT(input); |
1281 | 7.49M | PROTECT(x); |
1282 | | |
1283 | | /* Optimisation to prevent repeated recalculation */ |
1284 | 7.49M | size_t slen = strlen(translateChar(input)); |
1285 | | /* The mechanism to allow a class extending "environment" */ |
1286 | 7.49M | if( IS_S4_OBJECT(x) && TYPEOF(x) == OBJSXP ){ |
1287 | 0 | x = R_getS4DataSlot(x, ANYSXP); |
1288 | 0 | if(x == R_NilValue) |
1289 | 0 | errorcall(call, "$ operator not defined for this S4 class"); |
1290 | |
|
1291 | 0 | UNPROTECT(1); /* x */ |
1292 | 0 | PROTECT(x); |
1293 | 0 | } |
1294 | | |
1295 | | // isPairList(x) but *not* <DOTSXP> : |
1296 | 7.49M | if (TYPEOF(x) == LISTSXP || TYPEOF(x) == LANGSXP || TYPEOF(x) == NILSXP) { |
1297 | 11.0k | SEXP xmatch = R_NilValue; |
1298 | 11.0k | int havematch; |
1299 | 11.0k | havematch = 0; |
1300 | 15.6k | for (y = x ; y != R_NilValue ; y = CDR(y)) { |
1301 | 6.09k | switch(pstrmatch(TAG(y), input, slen)) { |
1302 | 1.52k | case EXACT_MATCH: |
1303 | 1.52k | y = CAR(y); |
1304 | 1.52k | RAISE_NAMED(y, NAMED(x)); |
1305 | 1.52k | UNPROTECT(2); /* input, x */ |
1306 | 1.52k | return y; |
1307 | 0 | case PARTIAL_MATCH: |
1308 | 0 | havematch++; |
1309 | 0 | xmatch = y; |
1310 | 0 | #ifdef SWITCH_TO_REFCNT |
1311 | 0 | if (IS_GETTER_CALL(call)) |
1312 | 0 | MARK_NOT_MUTABLE(y); |
1313 | 0 | #endif |
1314 | 0 | break; |
1315 | 4.57k | case NO_MATCH: |
1316 | 4.57k | break; |
1317 | 6.09k | } |
1318 | 6.09k | } |
1319 | 9.53k | if (havematch == 1) { /* unique partial match */ |
1320 | 0 | if(R_warn_partial_match_dollar) { |
1321 | 0 | SEXP target = TAG(xmatch); |
1322 | 0 | SEXP cond = |
1323 | 0 | R_makePartialMatchWarningCondition(call, |
1324 | 0 | input, |
1325 | 0 | target); |
1326 | 0 | PROTECT(cond); |
1327 | 0 | R_signalWarningCondition(cond); |
1328 | 0 | UNPROTECT(1); |
1329 | 0 | } |
1330 | 0 | y = CAR(xmatch); |
1331 | 0 | RAISE_NAMED(y, NAMED(x)); |
1332 | 0 | UNPROTECT(2); /* input, x */ |
1333 | 0 | return y; |
1334 | 0 | } |
1335 | 9.53k | UNPROTECT(2); /* input, x */ |
1336 | 9.53k | return R_NilValue; |
1337 | 9.53k | } |
1338 | 7.48M | else if (isVectorList(x)) { |
1339 | 6.27M | R_xlen_t i, n, imatch = -1; |
1340 | 6.27M | int havematch; |
1341 | 6.27M | SEXP nlist = getAttrib(x, R_NamesSymbol); |
1342 | | |
1343 | 6.27M | n = xlength(nlist); |
1344 | 6.27M | havematch = 0; |
1345 | 37.0M | for (i = 0 ; i < n ; i = i + 1) { |
1346 | 37.0M | switch(pstrmatch(STRING_ELT(nlist, i), input, slen)) { |
1347 | 6.18M | case EXACT_MATCH: |
1348 | 6.18M | y = VECTOR_ELT(x, i); |
1349 | 6.18M | RAISE_NAMED(y, NAMED(x)); |
1350 | 6.18M | UNPROTECT(2); /* input, x */ |
1351 | 6.18M | return y; |
1352 | 100 | case PARTIAL_MATCH: |
1353 | 100 | havematch++; |
1354 | 100 | if (havematch == 1) { |
1355 | | /* partial matches can cause aliasing in eval.c:evalseq |
1356 | | This is overkill, but alternative ways to prevent |
1357 | | the aliasing appear to be even worse */ |
1358 | 86 | y = VECTOR_ELT(x,i); |
1359 | 86 | #ifdef SWITCH_TO_REFCNT |
1360 | 86 | if (IS_GETTER_CALL(call)) |
1361 | 55 | MARK_NOT_MUTABLE(y); |
1362 | | #else |
1363 | | ENSURE_NAMEDMAX(y); |
1364 | | #endif |
1365 | 86 | SET_VECTOR_ELT(x,i,y); |
1366 | 86 | } |
1367 | 100 | imatch = i; |
1368 | 100 | break; |
1369 | 30.8M | case NO_MATCH: |
1370 | 30.8M | break; |
1371 | 37.0M | } |
1372 | 37.0M | } |
1373 | 84.9k | if(havematch == 1) { /* unique partial match */ |
1374 | 47 | if(R_warn_partial_match_dollar) { |
1375 | 0 | SEXP target = STRING_ELT(nlist, imatch); |
1376 | 0 | SEXP cond = |
1377 | 0 | R_makePartialMatchWarningCondition(call, |
1378 | 0 | input, |
1379 | 0 | target); |
1380 | 0 | PROTECT(cond); |
1381 | 0 | R_signalWarningCondition(cond); |
1382 | 0 | UNPROTECT(1); |
1383 | 0 | } |
1384 | 47 | y = VECTOR_ELT(x, imatch); |
1385 | 47 | RAISE_NAMED(y, NAMED(x)); |
1386 | 47 | UNPROTECT(2); /* input, x */ |
1387 | 47 | return y; |
1388 | 47 | } |
1389 | 84.9k | UNPROTECT(2); /* input, x */ |
1390 | 84.9k | return R_NilValue; |
1391 | 84.9k | } |
1392 | 1.21M | else if( isEnvironment(x) ){ |
1393 | 1.21M | y = R_findVarInFrame(x, installTrChar(input)); |
1394 | 1.21M | if( TYPEOF(y) == PROMSXP ) { |
1395 | 534 | PROTECT(y); |
1396 | 534 | y = eval(y, R_GlobalEnv); |
1397 | 534 | UNPROTECT(1); /* y */ |
1398 | 534 | } |
1399 | 1.21M | UNPROTECT(2); /* input, x */ |
1400 | 1.21M | if( y != R_UnboundValue ) { |
1401 | 1.21M | if (NAMED(y)) |
1402 | 1.21M | ENSURE_NAMEDMAX(y); |
1403 | 0 | else RAISE_NAMED(y, NAMED(x)); |
1404 | 1.21M | return(y); |
1405 | 1.21M | } |
1406 | 0 | return R_NilValue; |
1407 | 1.21M | } |
1408 | 95 | else if( isVectorAtomic(x) ){ |
1409 | 91 | errorcall(call, "$ operator is invalid for atomic vectors"); |
1410 | 91 | } |
1411 | 4 | else /* e.g. a function */ |
1412 | 4 | errorcallNotSubsettable(x, call); |
1413 | 95 | UNPROTECT(2); /* input, x */ |
1414 | 95 | return R_NilValue; |
1415 | 7.49M | } |