LCOV - code coverage report
Current view: top level - shumate/vector - shumate-vector-index.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 266 281 94.7 %
Date: 2024-05-11 21:41:31 Functions: 45 45 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 69 114 60.5 %

           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 : }

Generated by: LCOV version 1.14