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