1 #include "vctrs.h"
2 #include "type-data-frame.h"
3 #include "utils.h"
4 #include "slice.h"
5
vec_raw_size(SEXP x)6 static inline R_len_t vec_raw_size(SEXP x) {
7 SEXP dimensions = r_dim(x);
8
9 if (dimensions == R_NilValue || Rf_length(dimensions) == 0) {
10 return Rf_length(x);
11 }
12
13 if (TYPEOF(dimensions) != INTSXP) {
14 Rf_errorcall(R_NilValue, "Corrupt vector, `dim` attribute is not an integer vector.");
15 }
16
17 R_len_t size = INTEGER(dimensions)[0];
18
19 return size;
20 }
21
22
23 // [[ include("vctrs.h") ]]
vec_size(SEXP x)24 R_len_t vec_size(SEXP x) {
25 int nprot = 0;
26
27 struct vctrs_proxy_info info = vec_proxy_info(x);
28 PROTECT_PROXY_INFO(&info, &nprot);
29
30 SEXP data = info.proxy;
31
32 R_len_t size;
33 switch (info.type) {
34 case vctrs_type_null:
35 size = 0;
36 break;
37 case vctrs_type_logical:
38 case vctrs_type_integer:
39 case vctrs_type_double:
40 case vctrs_type_complex:
41 case vctrs_type_character:
42 case vctrs_type_raw:
43 case vctrs_type_list:
44 size = vec_raw_size(data);
45 break;
46
47 case vctrs_type_dataframe:
48 size = df_size(data);
49 break;
50
51 default:
52 stop_scalar_type(x, NULL);
53 }
54
55 UNPROTECT(nprot);
56 return size;
57 }
58 // [[ register() ]]
vctrs_size(SEXP x)59 SEXP vctrs_size(SEXP x) {
60 return Rf_ScalarInteger(vec_size(x));
61 }
62
list_sizes(SEXP x)63 SEXP list_sizes(SEXP x) {
64 if (!vec_is_list(x)) {
65 Rf_errorcall(R_NilValue, "`x` must be a list.");
66 }
67
68 R_len_t size = vec_size(x);
69
70 SEXP out = PROTECT(Rf_allocVector(INTSXP, size));
71 int* p_out = INTEGER(out);
72
73 for (R_len_t i = 0; i < size; ++i) {
74 SEXP elt = VECTOR_ELT(x, i);
75 p_out[i] = vec_size(elt);
76 }
77
78 UNPROTECT(1);
79 return out;
80 }
81
82 // [[ register() ]]
vctrs_list_sizes(SEXP x)83 SEXP vctrs_list_sizes(SEXP x) {
84 return list_sizes(x);
85 }
86
df_rownames_size(SEXP x)87 R_len_t df_rownames_size(SEXP x) {
88 for (SEXP attr = ATTRIB(x); attr != R_NilValue; attr = CDR(attr)) {
89 if (TAG(attr) != R_RowNamesSymbol) {
90 continue;
91 }
92
93 return rownames_size(CAR(attr));
94 }
95
96 return -1;
97 }
98
99 // For performance, avoid Rf_getAttrib() because it automatically transforms
100 // the rownames into an integer vector
df_size(SEXP x)101 R_len_t df_size(SEXP x) {
102 R_len_t n = df_rownames_size(x);
103
104 if (n < 0) {
105 Rf_errorcall(R_NilValue, "Corrupt data frame: row.names are missing");
106 }
107
108 return n;
109 }
110 // Supports bare lists as well
df_raw_size(SEXP x)111 R_len_t df_raw_size(SEXP x) {
112 R_len_t n = df_rownames_size(x);
113 if (n >= 0) {
114 return n;
115 }
116
117 return df_raw_size_from_list(x);
118 }
119
120 // [[ include("vctrs.h") ]]
df_raw_size_from_list(SEXP x)121 R_len_t df_raw_size_from_list(SEXP x) {
122 if (Rf_length(x) >= 1) {
123 return vec_size(VECTOR_ELT(x, 0));
124 } else {
125 return 0;
126 }
127 }
128
129 // [[ register() ]]
vctrs_df_size(SEXP x)130 SEXP vctrs_df_size(SEXP x) {
131 return r_int(df_raw_size(x));
132 }
133
134
135 // [[ include("vctrs.h") ]]
vec_recycle(SEXP x,R_len_t size,struct vctrs_arg * x_arg)136 SEXP vec_recycle(SEXP x, R_len_t size, struct vctrs_arg* x_arg) {
137 if (x == R_NilValue) {
138 return R_NilValue;
139 }
140
141 R_len_t n_x = vec_size(x);
142
143 if (n_x == size) {
144 return x;
145 }
146
147 if (n_x == 1L) {
148 SEXP i = PROTECT(compact_rep(1, size));
149 SEXP out = vec_slice_impl(x, i);
150
151 UNPROTECT(1);
152 return out;
153 }
154
155 stop_recycle_incompatible_size(n_x, size, x_arg);
156 }
157
158 // [[ register() ]]
vctrs_recycle(SEXP x,SEXP size_obj,SEXP x_arg)159 SEXP vctrs_recycle(SEXP x, SEXP size_obj, SEXP x_arg) {
160 if (x == R_NilValue || size_obj == R_NilValue) {
161 return R_NilValue;
162 }
163
164 size_obj = PROTECT(vec_cast(size_obj, vctrs_shared_empty_int, args_empty, args_empty));
165 R_len_t size = r_int_get(size_obj, 0);
166 UNPROTECT(1);
167
168 struct vctrs_arg x_arg_ = vec_as_arg(x_arg);
169
170 return vec_recycle(x, size, &x_arg_);
171 }
172
173 // [[ include("vctrs.h") ]]
vec_recycle_fallback(SEXP x,R_len_t size,struct vctrs_arg * x_arg)174 SEXP vec_recycle_fallback(SEXP x, R_len_t size, struct vctrs_arg* x_arg) {
175 if (x == R_NilValue) {
176 return R_NilValue;
177 }
178
179 R_len_t x_size = vec_size(x);
180
181 if (x_size == size) {
182 return x;
183 }
184
185 if (x_size == 1) {
186 SEXP subscript = PROTECT(Rf_allocVector(INTSXP, size));
187 r_int_fill(subscript, 1, size);
188
189 SEXP out = vec_slice_fallback(x, subscript);
190
191 UNPROTECT(1);
192 return out;
193 }
194
195 stop_recycle_incompatible_size(x_size, size, x_arg);
196 }
197
198
199 // [[ include("utils.h") ]]
size_validate(SEXP size,const char * arg)200 R_len_t size_validate(SEXP size, const char* arg) {
201 size = vec_cast(size, vctrs_shared_empty_int, args_empty, args_empty);
202
203 if (Rf_length(size) != 1) {
204 Rf_errorcall(R_NilValue, "`%s` must be a single integer.", arg);
205 }
206
207 int out = r_int_get(size, 0);
208
209 if (out == NA_INTEGER) {
210 Rf_errorcall(R_NilValue, "`%s` can't be missing.", arg);
211 }
212
213 return out;
214 }
215