Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2024 James Westman <james@jwestman.net>
3 : : *
4 : : * This library is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * This library is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : : * Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with this library; if not, see <https://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : /*
19 : : * Map styles can be very large with many layers, often having many similar expressions. For example,
20 : : * the GNOME Maps style has over 800 style layers for roads, and most of their filter expressions
21 : : * are different permutations of the same few geometry and feature data expressions. Instead of calculating
22 : : * every expression for every feature 800 times, we can build indexes for those expressions and use them
23 : : * to quickly filter features.
24 : : *
25 : : * The indexes are bitsets: each feature's bit is set if it matches the expression. It is very fast to
26 : : * combine these bitsets with bitwise AND, OR, and NOT operations.
27 : : */
28 : :
29 : : #include "shumate-vector-index-private.h"
30 : :
31 : : typedef struct {
32 : : /* Hash set of ShumateVectorValues that should have indexes */
33 : : GHashTable *values;
34 : : /* True if there should be an index of features that have any value for this field */
35 : : guint8 has_index;
36 : : } ShumateVectorIndexDescriptionField;
37 : :
38 : : typedef struct {
39 : : /* Map of field name to ShumateVectorIndexDescriptionField */
40 : : GHashTable *fields;
41 : : /* True if there should be geometry type indexes for the broad geometry types, not distinguishing single vs. multi */
42 : : guint8 broad_geometry_indexes;
43 : : /* True if there should be geometry type indexes that distinguish single vs. multi types*/
44 : : guint8 geometry_indexes;
45 : : } ShumateVectorIndexDescriptionLayer;
46 : :
47 : : /* A description of the fields and values that a set of expressions needs indexes for. */
48 : : struct _ShumateVectorIndexDescription {
49 : : /* Map of layer name to ShumateVectorIndexDescriptionLayer */
50 : : GHashTable *layers;
51 : : };
52 : :
53 : : typedef struct {
54 : : /* Map of value to GHashTable of ShumateVectorIndexBitset */
55 : : GHashTable *indexes;
56 : : /* Index of features that have any value for this field */
57 : : ShumateVectorIndexBitset *has_index;
58 : : } ShumateVectorIndexField;
59 : :
60 : : typedef struct {
61 : : /* Map of field name to ShumateVectorIndexField */
62 : : GHashTable *fields;
63 : : ShumateVectorIndexBitset *broad_geometry_type_indexes[3];
64 : : ShumateVectorIndexBitset *geometry_type_indexes[6];
65 : : } ShumateVectorIndexLayer;
66 : :
67 : : /* A set of indexes for a specific vector tile. */
68 : : struct _ShumateVectorIndex {
69 : : /* Map of layer index to ShumateVectorIndexLayer */
70 : : GHashTable *layers;
71 : : };
72 : :
73 : : static inline int
74 : 225 : n_units (int len)
75 : : {
76 : 225 : return (len + 31) / 32;
77 : : }
78 : :
79 : : ShumateVectorIndexBitset *
80 : 72 : shumate_vector_index_bitset_new (int len)
81 : : {
82 : 72 : ShumateVectorIndexBitset *bitset = g_new (ShumateVectorIndexBitset, 1);
83 : 72 : bitset->len = len;
84 [ - + - - ]: 72 : bitset->bits = g_new0 (guint32, n_units (len));
85 : 72 : return bitset;
86 : : }
87 : :
88 : : ShumateVectorIndexBitset *
89 : 6 : shumate_vector_index_bitset_copy (ShumateVectorIndexBitset *bitset)
90 : : {
91 : 6 : ShumateVectorIndexBitset *copy;
92 : :
93 [ + - ]: 6 : if (bitset == NULL)
94 : : return NULL;
95 : :
96 : 6 : copy = g_new (ShumateVectorIndexBitset, 1);
97 : 6 : copy->len = bitset->len;
98 : 6 : copy->bits = g_memdup2 (bitset->bits, n_units (bitset->len) * sizeof (guint32));
99 : 6 : return copy;
100 : : }
101 : :
102 : : void
103 : 78 : shumate_vector_index_bitset_free (ShumateVectorIndexBitset *bitset)
104 : : {
105 [ + - ]: 78 : if (bitset == NULL)
106 : : return;
107 : :
108 : 78 : g_free (bitset->bits);
109 : 78 : g_free (bitset);
110 : : }
111 : :
112 : : /* Sets the given bit of the bitset. */
113 : : void
114 : 42 : shumate_vector_index_bitset_set (ShumateVectorIndexBitset *bitset, guint bit)
115 : : {
116 : 42 : gsize unit = bit / 32;
117 : 42 : guint32 mask = 1 << (bit % 32);
118 : 42 : bitset->bits[unit] |= mask;
119 : 42 : }
120 : :
121 : : /* Returns the value of the given bit of the bitset. */
122 : : gboolean
123 : 54 : shumate_vector_index_bitset_get (ShumateVectorIndexBitset *bitset, guint bit)
124 : : {
125 : 54 : gsize unit = bit / 32;
126 : 54 : guint32 mask = 1 << (bit % 32);
127 : 54 : return (bitset->bits[unit] & mask) != 0;
128 : : }
129 : :
130 : : /* Clears the given bit of the bitset. */
131 : : void
132 : 6 : shumate_vector_index_bitset_clear (ShumateVectorIndexBitset *bitset, guint bit)
133 : : {
134 : 6 : gsize unit = bit / 32;
135 : 6 : guint32 mask = 1 << (bit % 32);
136 : 6 : bitset->bits[unit] &= ~mask;
137 : 6 : }
138 : :
139 : : /* Computes the bitwise AND of the two bitsets, storing the result in the first bitset. */
140 : : void
141 : 9 : shumate_vector_index_bitset_and (ShumateVectorIndexBitset *bitset, ShumateVectorIndexBitset *other)
142 : : {
143 [ + - ]: 9 : g_assert (bitset != NULL);
144 [ - + ]: 9 : g_assert (other != NULL);
145 [ + - ]: 9 : g_assert (bitset->len == other->len);
146 : :
147 [ + + ]: 27 : for (gsize i = 0; i < n_units (bitset->len); i++)
148 : 18 : bitset->bits[i] &= other->bits[i];
149 : 9 : }
150 : :
151 : : /* Computes the bitwise OR of the two bitsets, storing the result in the first bitset. */
152 : : void
153 : 12 : shumate_vector_index_bitset_or (ShumateVectorIndexBitset *bitset, ShumateVectorIndexBitset *other)
154 : : {
155 [ + - ]: 12 : g_assert (bitset != NULL);
156 [ - + ]: 12 : g_assert (other != NULL);
157 [ + - ]: 12 : g_assert (bitset->len == other->len);
158 : :
159 [ + + ]: 33 : for (gsize i = 0; i < n_units (bitset->len); i++)
160 : 21 : bitset->bits[i] |= other->bits[i];
161 : 12 : }
162 : :
163 : : /* Computes the bitwise inverse of the bitset in place. */
164 : : void
165 : 15 : shumate_vector_index_bitset_not (ShumateVectorIndexBitset *bitset)
166 : : {
167 [ + - ]: 15 : g_assert (bitset != NULL);
168 : :
169 [ + + ]: 30 : for (gsize i = 0; i < n_units (bitset->len); i++)
170 : 15 : bitset->bits[i] = ~bitset->bits[i];
171 : 15 : }
172 : :
173 : : /* Returns the next set bit after the given bit, or -1 if no bit is set after it. */
174 : : int
175 : 27 : shumate_vector_index_bitset_next (ShumateVectorIndexBitset *bitset, int start)
176 : : {
177 : 27 : int unit = start / 32;
178 : 27 : start = start % 32;
179 : :
180 [ + - + - ]: 27 : g_assert (start >= -1 && start < bitset->len);
181 : :
182 [ + + ]: 57 : for (gsize i = unit; i < n_units (bitset->len); i++)
183 : : {
184 : 51 : int nth = g_bit_nth_lsf (bitset->bits[i], start);
185 [ + + ]: 51 : if (nth != -1)
186 : : {
187 : 21 : int result = i * 32 + nth;
188 [ - + ]: 21 : if (result < bitset->len)
189 : : return result;
190 : : else
191 : 0 : return -1;
192 : : }
193 : 30 : start = -1;
194 : : }
195 : :
196 : : return -1;
197 : : }
198 : :
199 : : static ShumateVectorIndexField *
200 : 6 : shumate_vector_index_field_new (void)
201 : : {
202 : 6 : ShumateVectorIndexField *field = g_new0 (ShumateVectorIndexField, 1);
203 : 6 : field->indexes = g_hash_table_new_full (
204 : : (GHashFunc)shumate_vector_value_hash,
205 : : (GEqualFunc)shumate_vector_value_equal,
206 : : (GDestroyNotify)shumate_vector_value_free,
207 : : (GDestroyNotify)shumate_vector_index_bitset_free
208 : : );
209 : 6 : return field;
210 : : }
211 : :
212 : : static void
213 : 6 : shumate_vector_index_field_free (ShumateVectorIndexField *field)
214 : : {
215 : 6 : g_hash_table_destroy (field->indexes);
216 [ + + ]: 6 : g_clear_pointer (&field->has_index, shumate_vector_index_bitset_free);
217 : 6 : g_free (field);
218 : 6 : }
219 : :
220 : : static ShumateVectorIndexLayer *
221 : 12 : shumate_vector_index_layer_new (void)
222 : : {
223 : 12 : ShumateVectorIndexLayer *layer = g_new0 (ShumateVectorIndexLayer, 1);
224 : 12 : layer->fields = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) shumate_vector_index_field_free);
225 : 12 : return layer;
226 : : }
227 : :
228 : : static void
229 : 12 : shumate_vector_index_layer_free (ShumateVectorIndexLayer *layer)
230 : : {
231 : 12 : g_hash_table_destroy (layer->fields);
232 [ + + ]: 48 : for (int i = 0; i < 3; i++)
233 [ + + ]: 36 : g_clear_pointer (&layer->broad_geometry_type_indexes[i], shumate_vector_index_bitset_free);
234 [ + + ]: 84 : for (int i = 0; i < 6; i++)
235 [ + + ]: 72 : g_clear_pointer (&layer->geometry_type_indexes[i], shumate_vector_index_bitset_free);
236 : 12 : g_free (layer);
237 : 12 : }
238 : :
239 : : ShumateVectorIndex *
240 : 21 : shumate_vector_index_new (void)
241 : : {
242 : 21 : ShumateVectorIndex *index = g_new0 (ShumateVectorIndex, 1);
243 : 21 : index->layers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) shumate_vector_index_layer_free);
244 : 21 : return index;
245 : : }
246 : :
247 : : void
248 : 21 : shumate_vector_index_free (ShumateVectorIndex *index)
249 : : {
250 : 21 : g_hash_table_destroy (index->layers);
251 : 21 : g_free (index);
252 : 21 : }
253 : :
254 : : gboolean
255 : 21 : shumate_vector_index_has_layer (ShumateVectorIndex *self,
256 : : int layer_idx)
257 : : {
258 : 21 : return g_hash_table_contains (self->layers, GINT_TO_POINTER (layer_idx));
259 : : }
260 : :
261 : : static ShumateVectorIndexLayer *
262 : 33 : get_or_create_layer (ShumateVectorIndex *self,
263 : : int layer_idx)
264 : : {
265 : 33 : ShumateVectorIndexLayer *layer;
266 : :
267 : 33 : layer = g_hash_table_lookup (self->layers, GINT_TO_POINTER (layer_idx));
268 [ + + ]: 33 : if (layer == NULL)
269 : : {
270 : 12 : layer = shumate_vector_index_layer_new ();
271 : 12 : g_hash_table_insert (self->layers, GINT_TO_POINTER (layer_idx), layer);
272 : : }
273 : :
274 : 33 : return layer;
275 : : }
276 : :
277 : : static ShumateVectorIndexField *
278 : 6 : get_or_create_field (ShumateVectorIndex *self,
279 : : int layer_idx,
280 : : const char *field_name)
281 : : {
282 : 6 : ShumateVectorIndexLayer *layer = get_or_create_layer (self, layer_idx);
283 : 6 : ShumateVectorIndexField *field;
284 : :
285 : 6 : field = g_hash_table_lookup (layer->fields, field_name);
286 [ + - ]: 6 : if (field == NULL)
287 : : {
288 : 6 : field = shumate_vector_index_field_new ();
289 [ - + ]: 12 : g_hash_table_insert (layer->fields, g_strdup (field_name), field);
290 : : }
291 : :
292 : 6 : return field;
293 : : }
294 : :
295 : : void
296 : 3 : shumate_vector_index_add_bitset (ShumateVectorIndex *self,
297 : : int layer_idx,
298 : : const char *field_name,
299 : : ShumateVectorValue *value,
300 : : ShumateVectorIndexBitset *bitset)
301 : : {
302 : 3 : ShumateVectorIndexBitset *existing;
303 : 3 : ShumateVectorIndexField *field = get_or_create_field (self, layer_idx, field_name);
304 : :
305 : 3 : existing = g_hash_table_lookup (field->indexes, value);
306 [ - + ]: 3 : if (existing != NULL)
307 : : {
308 : 0 : shumate_vector_index_bitset_or (existing, bitset);
309 : 0 : shumate_vector_index_bitset_free (bitset);
310 : : }
311 : : else
312 : : {
313 : 3 : ShumateVectorValue *value_copy = g_new0 (ShumateVectorValue, 1);
314 : 3 : shumate_vector_value_copy (value, value_copy);
315 : 3 : g_hash_table_insert (field->indexes, value_copy, bitset);
316 : : }
317 : 3 : }
318 : :
319 : : void
320 : 3 : shumate_vector_index_add_bitset_has (ShumateVectorIndex *self,
321 : : int layer_idx,
322 : : const char *field_name,
323 : : ShumateVectorIndexBitset *bitset)
324 : : {
325 : 3 : ShumateVectorIndexField *field = get_or_create_field (self, layer_idx, field_name);
326 : :
327 [ - + ]: 3 : if (field->has_index != NULL)
328 : : {
329 : 0 : shumate_vector_index_bitset_or (field->has_index, bitset);
330 : 0 : shumate_vector_index_bitset_free (bitset);
331 : : }
332 : : else
333 : 3 : field->has_index = bitset;
334 : 3 : }
335 : :
336 : : void
337 : 9 : shumate_vector_index_add_bitset_broad_geometry_type (ShumateVectorIndex *self,
338 : : int layer_idx,
339 : : ShumateGeometryType type,
340 : : ShumateVectorIndexBitset *bitset)
341 : : {
342 : 9 : ShumateVectorIndexLayer *layer = get_or_create_layer (self, layer_idx);
343 : 9 : ShumateVectorIndexBitset *existing;
344 : 9 : int i;
345 : :
346 [ + + - + ]: 9 : switch (type)
347 : : {
348 : : case SHUMATE_GEOMETRY_TYPE_POINT:
349 : : i = 0;
350 : : break;
351 : 3 : case SHUMATE_GEOMETRY_TYPE_LINESTRING:
352 : 3 : i = 1;
353 : 3 : break;
354 : 3 : case SHUMATE_GEOMETRY_TYPE_POLYGON:
355 : 3 : i = 2;
356 : 3 : break;
357 : 0 : default:
358 : 0 : g_assert_not_reached ();
359 : : }
360 : :
361 : 9 : existing = layer->broad_geometry_type_indexes[i];
362 [ - + ]: 9 : if (existing != NULL)
363 : : {
364 : 0 : shumate_vector_index_bitset_or (existing, bitset);
365 : 0 : shumate_vector_index_bitset_free (bitset);
366 : : }
367 : : else
368 : 9 : layer->broad_geometry_type_indexes[i] = bitset;
369 : 9 : }
370 : :
371 : : void
372 : 18 : shumate_vector_index_add_bitset_geometry_type (ShumateVectorIndex *self,
373 : : int layer_idx,
374 : : ShumateGeometryType type,
375 : : ShumateVectorIndexBitset *bitset)
376 : : {
377 : 18 : ShumateVectorIndexLayer *layer = get_or_create_layer (self, layer_idx);
378 : 18 : ShumateVectorIndexBitset *existing;
379 : :
380 : 18 : existing = layer->geometry_type_indexes[type - 1];
381 [ - + ]: 18 : if (existing != NULL)
382 : : {
383 : 0 : shumate_vector_index_bitset_or (existing, bitset);
384 : 0 : shumate_vector_index_bitset_free (bitset);
385 : : }
386 : : else
387 : 18 : layer->geometry_type_indexes[type - 1] = bitset;
388 : 18 : }
389 : :
390 : : ShumateVectorIndexBitset *
391 : 6 : shumate_vector_index_get_bitset (ShumateVectorIndex *self,
392 : : int layer_idx,
393 : : const char *field_name,
394 : : ShumateVectorValue *value)
395 : : {
396 : 6 : ShumateVectorIndexLayer *layer;
397 : 6 : ShumateVectorIndexField *field;
398 : :
399 [ - + ]: 6 : if (self == NULL)
400 : : return NULL;
401 : :
402 : 6 : layer = g_hash_table_lookup (self->layers, GINT_TO_POINTER (layer_idx));
403 [ - + ]: 6 : if (layer == NULL)
404 : : return NULL;
405 : :
406 : 6 : field = g_hash_table_lookup (layer->fields, field_name);
407 [ - + ]: 6 : if (field == NULL)
408 : : return NULL;
409 : :
410 : 6 : return g_hash_table_lookup (field->indexes, value);
411 : : }
412 : :
413 : : ShumateVectorIndexBitset *
414 : 3 : shumate_vector_index_get_bitset_has (ShumateVectorIndex *self,
415 : : int layer_idx,
416 : : const char *field_name)
417 : : {
418 : 3 : ShumateVectorIndexLayer *layer;
419 : 3 : ShumateVectorIndexField *field;
420 : :
421 [ - + ]: 3 : if (self == NULL)
422 : : return NULL;
423 : :
424 : 3 : layer = g_hash_table_lookup (self->layers, GINT_TO_POINTER (layer_idx));
425 [ - + ]: 3 : if (layer == NULL)
426 : : return NULL;
427 : :
428 : 3 : field = g_hash_table_lookup (layer->fields, field_name);
429 [ - + ]: 3 : if (field == NULL)
430 : : return NULL;
431 : :
432 : 3 : return field->has_index;
433 : : }
434 : :
435 : : ShumateVectorIndexBitset *
436 : 3 : shumate_vector_index_get_bitset_broad_geometry_type (ShumateVectorIndex *self,
437 : : int layer_idx,
438 : : ShumateGeometryType type)
439 : : {
440 : 3 : ShumateVectorIndexLayer *layer;
441 : :
442 [ - + ]: 3 : if (self == NULL)
443 : : return NULL;
444 : :
445 : 3 : layer = g_hash_table_lookup (self->layers, GINT_TO_POINTER (layer_idx));
446 [ - + ]: 3 : if (layer == NULL)
447 : : return NULL;
448 : :
449 [ - - + - ]: 3 : switch (type)
450 : : {
451 : 0 : case SHUMATE_GEOMETRY_TYPE_POINT:
452 : 0 : return layer->broad_geometry_type_indexes[0];
453 : 3 : case SHUMATE_GEOMETRY_TYPE_LINESTRING:
454 : 3 : return layer->broad_geometry_type_indexes[1];
455 : 0 : case SHUMATE_GEOMETRY_TYPE_POLYGON:
456 : 0 : return layer->broad_geometry_type_indexes[2];
457 : : default:
458 : : return NULL;
459 : : }
460 : : }
461 : :
462 : : ShumateVectorIndexBitset *
463 : 3 : shumate_vector_index_get_bitset_geometry_type (ShumateVectorIndex *self,
464 : : int layer_idx,
465 : : ShumateGeometryType type)
466 : : {
467 : 3 : ShumateVectorIndexLayer *layer;
468 : :
469 [ + - ]: 3 : g_assert (type >= SHUMATE_GEOMETRY_TYPE_POINT && type <= SHUMATE_GEOMETRY_TYPE_MULTIPOLYGON);
470 : :
471 [ - + ]: 3 : if (self == NULL)
472 : : return NULL;
473 : :
474 : 3 : layer = g_hash_table_lookup (self->layers, GINT_TO_POINTER (layer_idx));
475 [ - + ]: 3 : if (layer == NULL)
476 : : return NULL;
477 : :
478 : 3 : return layer->geometry_type_indexes[type - 1];
479 : : }
480 : :
481 : : static ShumateVectorIndexDescriptionField *
482 : 12 : shumate_vector_index_description_field_new (void)
483 : : {
484 : 12 : ShumateVectorIndexDescriptionField *field = g_new0 (ShumateVectorIndexDescriptionField, 1);
485 : 12 : field->values = g_hash_table_new_full ((GHashFunc)shumate_vector_value_hash, (GEqualFunc)shumate_vector_value_equal, (GDestroyNotify)shumate_vector_value_free, NULL);
486 : 12 : return field;
487 : : }
488 : :
489 : : static void
490 : 12 : shumate_vector_index_description_field_free (ShumateVectorIndexDescriptionField *field)
491 : : {
492 : 12 : g_hash_table_destroy (field->values);
493 : 12 : g_free (field);
494 : 12 : }
495 : :
496 : : static ShumateVectorIndexDescriptionLayer *
497 : 21 : shumate_vector_index_description_layer_new (void)
498 : : {
499 : 21 : ShumateVectorIndexDescriptionLayer *layer = g_new0 (ShumateVectorIndexDescriptionLayer, 1);
500 : 21 : layer->fields = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) shumate_vector_index_description_field_free);
501 : 21 : return layer;
502 : : }
503 : :
504 : : static void
505 : 21 : shumate_vector_index_description_layer_free (ShumateVectorIndexDescriptionLayer *layer)
506 : : {
507 : 21 : g_hash_table_destroy (layer->fields);
508 : 21 : g_free (layer);
509 : 21 : }
510 : :
511 : : /* Creates a new index description, which describes the indexes that a set of expressions will use. */
512 : : ShumateVectorIndexDescription *
513 : 30 : shumate_vector_index_description_new (void)
514 : : {
515 : 30 : ShumateVectorIndexDescription *desc = g_new0 (ShumateVectorIndexDescription, 1);
516 : 30 : desc->layers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) shumate_vector_index_description_layer_free);
517 : 30 : return desc;
518 : : }
519 : :
520 : : void
521 : 30 : shumate_vector_index_description_free (ShumateVectorIndexDescription *description)
522 : : {
523 : 30 : g_hash_table_destroy (description->layers);
524 : 30 : g_free (description);
525 : 30 : }
526 : :
527 : : /* Returns whether the index description has any indexes for the given layer. */
528 : : gboolean
529 : 33 : shumate_vector_index_description_has_layer (ShumateVectorIndexDescription *description,
530 : : const char *layer_name)
531 : : {
532 : 33 : return g_hash_table_contains (description->layers, layer_name);
533 : : }
534 : :
535 : : /* Returns whether the index description has any indexes for the given field. */
536 : : gboolean
537 : 18 : shumate_vector_index_description_has_field (ShumateVectorIndexDescription *description,
538 : : const char *layer_name,
539 : : const char *field_name)
540 : : {
541 : 18 : ShumateVectorIndexDescriptionLayer *layer = g_hash_table_lookup (description->layers, layer_name);
542 [ + - ]: 18 : if (layer == NULL)
543 : : return FALSE;
544 : :
545 : 18 : return g_hash_table_contains (layer->fields, field_name);
546 : : }
547 : :
548 : : /* Returns whether the index description has an index for the given key=value pair. */
549 : : gboolean
550 : 12 : shumate_vector_index_description_has_value (ShumateVectorIndexDescription *description,
551 : : const char *layer_name,
552 : : const char *field_name,
553 : : ShumateVectorValue *value)
554 : : {
555 : 12 : ShumateVectorIndexDescriptionLayer *layer;
556 : 12 : ShumateVectorIndexDescriptionField *field;
557 : :
558 : 12 : layer = g_hash_table_lookup (description->layers, layer_name);
559 [ - + ]: 12 : if (layer == NULL)
560 : : return FALSE;
561 : :
562 : 12 : field = g_hash_table_lookup (layer->fields, field_name);
563 [ - + ]: 12 : if (field == NULL)
564 : : return FALSE;
565 : :
566 : 12 : return g_hash_table_contains (field->values, value);
567 : : }
568 : :
569 : : /* Returns whether the index description has an index for features with any value for the
570 : : given field. */
571 : : gboolean
572 : 12 : shumate_vector_index_description_has_field_has_index (ShumateVectorIndexDescription *description,
573 : : const char *layer_name,
574 : : const char *field_name)
575 : : {
576 : 12 : ShumateVectorIndexDescriptionLayer *layer;
577 : 12 : ShumateVectorIndexDescriptionField *field;
578 : :
579 : 12 : layer = g_hash_table_lookup (description->layers, layer_name);
580 [ - + ]: 12 : if (layer == NULL)
581 : : return FALSE;
582 : :
583 : 12 : field = g_hash_table_lookup (layer->fields, field_name);
584 [ - + ]: 12 : if (field == NULL)
585 : : return FALSE;
586 : :
587 : 12 : return field->has_index;
588 : : }
589 : :
590 : : /* Returns whether the index description has broad geometry type indexes. */
591 : : gboolean
592 : 24 : shumate_vector_index_description_has_broad_geometry_type (ShumateVectorIndexDescription *description,
593 : : const char *layer_name)
594 : : {
595 : 24 : ShumateVectorIndexDescriptionLayer *layer;
596 : :
597 : 24 : layer = g_hash_table_lookup (description->layers, layer_name);
598 [ + - ]: 24 : if (layer == NULL)
599 : : return FALSE;
600 : :
601 : 24 : return layer->broad_geometry_indexes;
602 : : }
603 : :
604 : : /* Returns whether the index description has geometry type indexes that distinguish single vs. multi geometries. */
605 : : gboolean
606 : 24 : shumate_vector_index_description_has_geometry_type (ShumateVectorIndexDescription *description,
607 : : const char *layer_name)
608 : : {
609 : 24 : ShumateVectorIndexDescriptionLayer *layer;
610 : :
611 : 24 : layer = g_hash_table_lookup (description->layers, layer_name);
612 [ + - ]: 24 : if (layer == NULL)
613 : : return FALSE;
614 : :
615 : 24 : return layer->geometry_indexes;
616 : : }
617 : :
618 : : static ShumateVectorIndexDescriptionLayer *
619 : 27 : get_or_create_desc_layer (ShumateVectorIndexDescription *desc,
620 : : const char *layer)
621 : : {
622 : 27 : ShumateVectorIndexDescriptionLayer *layer_desc;
623 : :
624 : 27 : layer_desc = g_hash_table_lookup (desc->layers, layer);
625 [ + + ]: 27 : if (layer_desc == NULL)
626 : : {
627 : 21 : layer_desc = shumate_vector_index_description_layer_new ();
628 [ - + ]: 42 : g_hash_table_insert (desc->layers, g_strdup (layer), layer_desc);
629 : : }
630 : :
631 : 27 : return layer_desc;
632 : : }
633 : :
634 : : static ShumateVectorIndexDescriptionField *
635 : 15 : get_or_create_desc_field (ShumateVectorIndexDescription *desc,
636 : : const char *layer,
637 : : const char *field)
638 : : {
639 : 15 : ShumateVectorIndexDescriptionLayer *layer_desc = get_or_create_desc_layer (desc, layer);
640 : 15 : ShumateVectorIndexDescriptionField *field_desc;
641 : :
642 : 15 : field_desc = g_hash_table_lookup (layer_desc->fields, field);
643 [ + + ]: 15 : if (field_desc == NULL)
644 : : {
645 : 12 : field_desc = shumate_vector_index_description_field_new ();
646 [ - + ]: 24 : g_hash_table_insert (layer_desc->fields, g_strdup (field), field_desc);
647 : : }
648 : :
649 : 15 : return field_desc;
650 : : }
651 : :
652 : : /* Add an index for the given key=value pair. */
653 : : void
654 : 9 : shumate_vector_index_description_add (ShumateVectorIndexDescription *desc,
655 : : const char *layer,
656 : : const char *field,
657 : : ShumateVectorValue *value)
658 : : {
659 : 9 : ShumateVectorIndexDescriptionField *field_desc = get_or_create_desc_field (desc, layer, field);
660 : 9 : ShumateVectorValue *value_copy;
661 : :
662 : 9 : value_copy = g_new0 (ShumateVectorValue, 1);
663 : 9 : shumate_vector_value_copy (value, value_copy);
664 : 9 : g_hash_table_insert (field_desc->values, value_copy, value_copy);
665 : 9 : }
666 : :
667 : : /* Add an index for features that have any value for the given field. */
668 : : void
669 : 6 : shumate_vector_index_description_add_has_index (ShumateVectorIndexDescription *desc,
670 : : const char *layer,
671 : : const char *field)
672 : : {
673 : 6 : ShumateVectorIndexDescriptionField *field_desc = get_or_create_desc_field (desc, layer, field);
674 : 6 : field_desc->has_index = TRUE;
675 : 6 : }
676 : :
677 : : /* Add geometry indexes to the index description. "Broad" indexes only index point/line/polygon,
678 : : not whether the geometry is a single or multi geometry. This is very common and is faster
679 : : to calculate. */
680 : : void
681 : 6 : shumate_vector_index_description_add_broad_geometry_type (ShumateVectorIndexDescription *desc,
682 : : const char *layer)
683 : : {
684 : 6 : ShumateVectorIndexDescriptionLayer *layer_desc = get_or_create_desc_layer (desc, layer);
685 : 6 : layer_desc->broad_geometry_indexes = TRUE;
686 : 6 : }
687 : :
688 : : /* Add geometry indexes to the index description. These indexes will distinguish single vs. multi geometries. */
689 : : void
690 : 6 : shumate_vector_index_description_add_geometry_type (ShumateVectorIndexDescription *desc,
691 : : const char *layer)
692 : : {
693 : 6 : ShumateVectorIndexDescriptionLayer *layer_desc = get_or_create_desc_layer (desc, layer);
694 : 6 : layer_desc->geometry_indexes = TRUE;
695 : 6 : }
|