1 #define R_NO_REMAP
2 #include <R.h>
3 #include <Rinternals.h>
4 #include "wk-v1.h"
5
6 typedef struct {
7 wk_handler_t* next;
8 int recursion_depth;
9 int recursion_depth_out;
10 int recursion_depth_threshold;
11 wk_vector_meta_t vector_meta;
12 int feature_id;
13 int feature_id_out;
14 int add_details;
15 SEXP details;
16 int* details_ptr[1];
17 R_xlen_t details_size;
18 } flatten_filter_t;
19
20 #define HANDLE_OR_RETURN(expr) \
21 result = expr; \
22 if (result == WK_ABORT_FEATURE) { \
23 Rf_error("wk_flatten_filter() does not support WK_ABORT_FEATURE"); \
24 } \
25 if (result != WK_CONTINUE) return result
26
27 #define META_IS_COLLECTION(meta) \
28 ((meta->geometry_type == WK_GEOMETRY) || \
29 (meta->geometry_type == WK_MULTIPOINT) || \
30 (meta->geometry_type == WK_MULTILINESTRING) || \
31 (meta->geometry_type == WK_MULTIPOLYGON) || \
32 (meta->geometry_type == WK_GEOMETRYCOLLECTION))
33
wk_flatten_filter_keep(flatten_filter_t * flatten_filter,const wk_meta_t * meta)34 static inline int wk_flatten_filter_keep(flatten_filter_t* flatten_filter, const wk_meta_t* meta) {
35 int is_collection = META_IS_COLLECTION(meta);
36 int recursion_level_above_threshold = flatten_filter->recursion_depth >= flatten_filter->recursion_depth_threshold;
37 return !is_collection || recursion_level_above_threshold;
38 }
39
wk_flatten_filter_init_details(flatten_filter_t * flatten_filter,R_xlen_t initial_size)40 static inline void wk_flatten_filter_init_details(flatten_filter_t* flatten_filter, R_xlen_t initial_size) {
41 if (!flatten_filter->add_details) {
42 return;
43 }
44
45 if (initial_size == WK_VECTOR_SIZE_UNKNOWN) {
46 initial_size = 1024;
47 }
48
49 flatten_filter->feature_id = -1;
50
51 if (flatten_filter->details != R_NilValue) {
52 R_ReleaseObject(flatten_filter->details); // # nocov
53 }
54
55 const char* names[] = {"feature_id", ""};
56 flatten_filter->details = PROTECT(Rf_mkNamed(VECSXP, names));
57 R_PreserveObject(flatten_filter->details);
58 UNPROTECT(1);
59
60 flatten_filter->details_size = initial_size;
61 for (int i = 0; i < 1; i++) {
62 SEXP item = PROTECT(Rf_allocVector(INTSXP, flatten_filter->details_size));
63 SET_VECTOR_ELT(flatten_filter->details, i, item);
64 flatten_filter->details_ptr[i] = INTEGER(item);
65 UNPROTECT(1);
66 }
67 }
68
wk_flatten_filter_append_details(flatten_filter_t * flatten_filter)69 static inline void wk_flatten_filter_append_details(flatten_filter_t* flatten_filter) {
70 if (flatten_filter->details == R_NilValue) {
71 return;
72 }
73
74 if (flatten_filter->feature_id_out >= flatten_filter->details_size) {
75 R_xlen_t new_size = flatten_filter->details_size * 2 + 1;
76 for (int i = 0; i < 1; i++) {
77 SEXP new_item = PROTECT(Rf_allocVector(INTSXP, new_size));
78 memcpy(INTEGER(new_item), INTEGER(VECTOR_ELT(flatten_filter->details, i)), flatten_filter->details_size * sizeof(int));
79 SET_VECTOR_ELT(flatten_filter->details, i, new_item);
80 flatten_filter->details_ptr[i] = INTEGER(new_item);
81 UNPROTECT(1);
82 }
83
84 flatten_filter->details_size = new_size;
85 }
86
87 flatten_filter->details_ptr[0][flatten_filter->feature_id_out] = flatten_filter->feature_id + 1;
88 }
89
wk_flatten_filter_finalize_details(flatten_filter_t * flatten_filter)90 static inline void wk_flatten_filter_finalize_details(flatten_filter_t* flatten_filter) {
91 if (flatten_filter->details == R_NilValue) {
92 return;
93 }
94
95 flatten_filter->feature_id_out++;
96
97 if (flatten_filter->feature_id_out != flatten_filter->details_size) {
98 for (int i = 0; i < 1; i++) {
99 SEXP new_item = PROTECT(Rf_allocVector(INTSXP, flatten_filter->feature_id_out));
100 memcpy(INTEGER(new_item), INTEGER(VECTOR_ELT(flatten_filter->details, i)), flatten_filter->feature_id_out * sizeof(int));
101 SET_VECTOR_ELT(flatten_filter->details, i, new_item);
102 UNPROTECT(1);
103 }
104
105 flatten_filter->details_size = flatten_filter->feature_id_out;
106 }
107 }
108
wk_flatten_filter_initialize(int * dirty,void * handler_data)109 void wk_flatten_filter_initialize(int* dirty, void* handler_data) {
110 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
111 *dirty = 1;
112 flatten_filter->next->initialize(&flatten_filter->next->dirty, flatten_filter->next->handler_data);
113 }
114
wk_flatten_filter_vector_start(const wk_vector_meta_t * meta,void * handler_data)115 int wk_flatten_filter_vector_start(const wk_vector_meta_t* meta, void* handler_data) {
116 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
117
118 flatten_filter->feature_id_out = -1;
119 flatten_filter->recursion_depth_out = 0;
120
121 memcpy(&(flatten_filter->vector_meta), meta, sizeof(wk_vector_meta_t));
122 if (flatten_filter->recursion_depth_threshold > 0) {
123 if (META_IS_COLLECTION(meta)) {
124 flatten_filter->vector_meta.size = WK_VECTOR_SIZE_UNKNOWN;
125 }
126
127 if (meta->geometry_type == WK_MULTIPOINT) {
128 flatten_filter->vector_meta.geometry_type = WK_POINT;
129 } else if (meta->geometry_type == WK_MULTILINESTRING) {
130 flatten_filter->vector_meta.geometry_type = WK_LINESTRING;
131 } else if (meta->geometry_type == WK_MULTIPOLYGON) {
132 flatten_filter->vector_meta.geometry_type = WK_POLYGON;
133 } else if (meta->geometry_type == WK_GEOMETRYCOLLECTION) {
134 flatten_filter->vector_meta.geometry_type = WK_GEOMETRY;
135 }
136 }
137
138 wk_flatten_filter_init_details(flatten_filter, flatten_filter->vector_meta.size);
139
140 return flatten_filter->next->vector_start(&(flatten_filter->vector_meta), flatten_filter->next->handler_data);
141 }
142
wk_flatten_filter_vector_end(const wk_vector_meta_t * meta,void * handler_data)143 SEXP wk_flatten_filter_vector_end(const wk_vector_meta_t* meta, void* handler_data) {
144 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
145 SEXP result = PROTECT(flatten_filter->next->vector_end(&(flatten_filter->vector_meta), flatten_filter->next->handler_data));
146 if (result != R_NilValue) {
147 wk_flatten_filter_finalize_details(flatten_filter);
148 Rf_setAttrib(result, Rf_install("wk_details"), flatten_filter->details);
149 }
150 UNPROTECT(1);
151 return result;
152 }
153
wk_flatten_filter_feature_start(const wk_vector_meta_t * meta,R_xlen_t feat_id,void * handler_data)154 int wk_flatten_filter_feature_start(const wk_vector_meta_t* meta, R_xlen_t feat_id, void* handler_data) {
155 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
156 flatten_filter->feature_id++;
157 flatten_filter->recursion_depth = 0;
158 return WK_CONTINUE;
159 }
160
wk_flatten_filter_feature_null(void * handler_data)161 int wk_flatten_filter_feature_null(void* handler_data) {
162 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
163 int result;
164
165 flatten_filter->feature_id_out++;
166 wk_flatten_filter_append_details(flatten_filter);
167
168 HANDLE_OR_RETURN(flatten_filter->next->feature_start(&(flatten_filter->vector_meta), flatten_filter->feature_id_out, flatten_filter->next->handler_data));
169 result = flatten_filter->next->null_feature(flatten_filter->next->handler_data);
170 if (result != WK_CONTINUE) {
171 return result;
172 }
173 return flatten_filter->next->feature_end(&(flatten_filter->vector_meta), flatten_filter->feature_id_out, flatten_filter->next->handler_data);
174 }
175
wk_flatten_filter_feature_end(const wk_vector_meta_t * meta,R_xlen_t feat_id,void * handler_data)176 int wk_flatten_filter_feature_end(const wk_vector_meta_t* meta, R_xlen_t feat_id, void* handler_data) {
177 return WK_CONTINUE;
178 }
179
wk_flatten_filter_geometry_start(const wk_meta_t * meta,uint32_t part_id,void * handler_data)180 int wk_flatten_filter_geometry_start(const wk_meta_t* meta, uint32_t part_id, void* handler_data) {
181 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
182 int result;
183
184 int keep = wk_flatten_filter_keep(flatten_filter, meta);
185 flatten_filter->recursion_depth++;
186 flatten_filter->recursion_depth_out += keep;
187
188 if (keep) {
189 uint32_t part_id_out;
190 if (flatten_filter->recursion_depth_out > 1) {
191 part_id_out = part_id;
192 } else {
193 part_id_out = WK_PART_ID_NONE;
194 flatten_filter->feature_id_out++;
195 wk_flatten_filter_append_details(flatten_filter);
196 HANDLE_OR_RETURN(flatten_filter->next->feature_start(&(flatten_filter->vector_meta), flatten_filter->feature_id_out, flatten_filter->next->handler_data));
197 }
198
199 HANDLE_OR_RETURN(flatten_filter->next->geometry_start(meta, part_id_out, flatten_filter->next->handler_data));
200 }
201
202 return WK_CONTINUE;
203 }
204
wk_flatten_filter_geometry_end(const wk_meta_t * meta,uint32_t part_id,void * handler_data)205 int wk_flatten_filter_geometry_end(const wk_meta_t* meta, uint32_t part_id, void* handler_data) {
206 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
207 int result;
208
209 flatten_filter->recursion_depth--;
210 int keep = wk_flatten_filter_keep(flatten_filter, meta);
211 flatten_filter->recursion_depth_out -= keep;
212
213 if (keep) {
214 uint32_t part_id_out = flatten_filter->recursion_depth_out > 0 ? part_id : WK_PART_ID_NONE;
215 HANDLE_OR_RETURN(flatten_filter->next->geometry_end(meta, part_id_out, flatten_filter->next->handler_data));
216
217 if (flatten_filter->recursion_depth_out == 0) {
218 HANDLE_OR_RETURN(flatten_filter->next->feature_end(&(flatten_filter->vector_meta), flatten_filter->feature_id_out, flatten_filter->next->handler_data));
219 }
220 }
221
222 return WK_CONTINUE;
223 }
224
wk_flatten_filter_ring_start(const wk_meta_t * meta,uint32_t size,uint32_t ring_id,void * handler_data)225 int wk_flatten_filter_ring_start(const wk_meta_t* meta, uint32_t size, uint32_t ring_id, void* handler_data) {
226 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
227 return flatten_filter->next->ring_start(meta, size, ring_id, flatten_filter->next->handler_data);
228 }
229
wk_flatten_filter_ring_end(const wk_meta_t * meta,uint32_t size,uint32_t ring_id,void * handler_data)230 int wk_flatten_filter_ring_end(const wk_meta_t* meta, uint32_t size, uint32_t ring_id, void* handler_data) {
231 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
232 return flatten_filter->next->ring_end(meta, size, ring_id, flatten_filter->next->handler_data);
233 }
234
wk_flatten_filter_coord(const wk_meta_t * meta,const double * coord,uint32_t feature_id_out,void * handler_data)235 int wk_flatten_filter_coord(const wk_meta_t* meta, const double* coord, uint32_t feature_id_out, void* handler_data) {
236 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
237 return flatten_filter->next->coord(meta, coord, feature_id_out, flatten_filter->next->handler_data);
238 }
239
wk_flatten_filter_error(const char * message,void * handler_data)240 int wk_flatten_filter_error(const char* message, void* handler_data) {
241 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
242 return flatten_filter->next->error(message, flatten_filter->next->handler_data);
243 }
244
wk_flatten_filter_deinitialize(void * handler_data)245 void wk_flatten_filter_deinitialize(void* handler_data) {
246 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
247 if (flatten_filter->details != R_NilValue) {
248 R_ReleaseObject(flatten_filter->details);
249 flatten_filter->details = R_NilValue;
250 }
251 flatten_filter->next->deinitialize(flatten_filter->next->handler_data);
252 }
253
wk_flatten_filter_finalize(void * handler_data)254 void wk_flatten_filter_finalize(void* handler_data) {
255 flatten_filter_t* flatten_filter = (flatten_filter_t*) handler_data;
256 if (flatten_filter != NULL) {
257 // finalizer for flatten_filter->next is run by the externalptr finalizer
258 // and should not be called here
259 free(flatten_filter);
260 }
261 }
262
wk_c_flatten_filter_new(SEXP handler_xptr,SEXP max_depth,SEXP add_details)263 SEXP wk_c_flatten_filter_new(SEXP handler_xptr, SEXP max_depth, SEXP add_details) {
264 int max_depth_int = INTEGER(max_depth)[0];
265 int add_details_int = LOGICAL(add_details)[0];
266
267 wk_handler_t* handler = wk_handler_create();
268
269 handler->initialize = &wk_flatten_filter_initialize;
270 handler->vector_start = &wk_flatten_filter_vector_start;
271 handler->vector_end = &wk_flatten_filter_vector_end;
272
273 handler->feature_start = &wk_flatten_filter_feature_start;
274 handler->null_feature = &wk_flatten_filter_feature_null;
275 handler->feature_end = &wk_flatten_filter_feature_end;
276
277 handler->geometry_start = &wk_flatten_filter_geometry_start;
278 handler->geometry_end = &wk_flatten_filter_geometry_end;
279
280 handler->ring_start = &wk_flatten_filter_ring_start;
281 handler->ring_end = &wk_flatten_filter_ring_end;
282
283 handler->coord = &wk_flatten_filter_coord;
284
285 handler->error = &wk_flatten_filter_error;
286
287 handler->deinitialize = &wk_flatten_filter_deinitialize;
288 handler->finalizer = &wk_flatten_filter_finalize;
289
290 flatten_filter_t* flatten_filter = (flatten_filter_t*) malloc(sizeof(flatten_filter_t));
291 if (flatten_filter == NULL) {
292 wk_handler_destroy(handler); // # nocov
293 Rf_error("Failed to alloc handler data"); // # nocov
294 }
295
296 flatten_filter->next = R_ExternalPtrAddr(handler_xptr);
297 if (flatten_filter->next->api_version != 1) {
298 Rf_error("Can't run a wk_handler with api_version '%d'", flatten_filter->next->api_version); // # nocov
299 }
300
301 WK_VECTOR_META_RESET(flatten_filter->vector_meta, WK_GEOMETRY);
302 flatten_filter->add_details = add_details_int;
303 flatten_filter->recursion_depth_threshold = max_depth_int;
304 flatten_filter->recursion_depth = 0;
305 flatten_filter->recursion_depth_out = 0;
306 flatten_filter->details = R_NilValue;
307 flatten_filter->details_size = 0;
308 flatten_filter->feature_id = 0;
309 flatten_filter->feature_id_out = 0;
310
311 handler->handler_data = flatten_filter;
312
313 // include the external pointer as a tag for this external pointer
314 // which guarnatees that it will not be garbage collected until
315 // this object is garbage collected
316 return wk_handler_create_xptr(handler, handler_xptr, R_NilValue);
317 }
318
319