LCOV - code coverage report
Current view: top level - shumate - shumate-memory-cache.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 98 115 85.2 %
Date: 2024-05-11 21:41:31 Functions: 15 17 88.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 27 48 56.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2010-2013 Jiri Techet <techet@gmail.com>
       3                 :            :  * Copyright (C) 2019 Marcus Lundblad <ml@update.uu.se>
       4                 :            :  *
       5                 :            :  * This library is free software; you can redistribute it and/or
       6                 :            :  * modify it under the terms of the GNU Lesser General Public
       7                 :            :  * License as published by the Free Software Foundation; either
       8                 :            :  * version 2.1 of the License, or (at your option) any later version.
       9                 :            :  *
      10                 :            :  * This library is distributed in the hope that it will be useful,
      11                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13                 :            :  * Lesser General Public License for more details.
      14                 :            :  *
      15                 :            :  * You should have received a copy of the GNU Lesser General Public
      16                 :            :  * License along with this library; if not, write to the Free Software
      17                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      18                 :            :  */
      19                 :            : 
      20                 :            : /**
      21                 :            :  * ShumateMemoryCache:
      22                 :            :  *
      23                 :            :  * A cache that stores and retrieves tiles from the memory. The cache contents
      24                 :            :  * is not preserved between application restarts so this cache serves mostly as
      25                 :            :  * a quick access temporary cache to the most recently used tiles.
      26                 :            :  */
      27                 :            : 
      28                 :            : #include "shumate-memory-cache-private.h"
      29                 :            : #include "shumate-tile-private.h"
      30                 :            : 
      31                 :            : #include <glib.h>
      32                 :            : #include <string.h>
      33                 :            : 
      34                 :            : enum
      35                 :            : {
      36                 :            :   PROP_0,
      37                 :            :   PROP_SIZE_LIMIT,
      38                 :            :   N_PROPS
      39                 :            : };
      40                 :            : 
      41                 :            : static GParamSpec *properties [N_PROPS];
      42                 :            : 
      43                 :            : struct _ShumateMemoryCache
      44                 :            : {
      45                 :            :   GObject parent_instance;
      46                 :            : 
      47                 :            :   guint size_limit;
      48                 :            :   GQueue *queue;
      49                 :            :   GHashTable *hash_table;
      50                 :            : };
      51                 :            : 
      52   [ +  +  +  - ]:        162 : G_DEFINE_TYPE (ShumateMemoryCache, shumate_memory_cache, G_TYPE_OBJECT);
      53                 :            : 
      54                 :            : typedef struct
      55                 :            : {
      56                 :            :   char *key;
      57                 :            :   GdkPaintable *paintable;
      58                 :            :   GPtrArray *symbols;
      59                 :            : } QueueMember;
      60                 :            : 
      61                 :            : 
      62                 :            : static void
      63                 :          0 : shumate_memory_cache_get_property (GObject    *object,
      64                 :            :                                    guint       property_id,
      65                 :            :                                    GValue     *value,
      66                 :            :                                    GParamSpec *pspec)
      67                 :            : {
      68                 :          0 :   ShumateMemoryCache *memory_cache = SHUMATE_MEMORY_CACHE (object);
      69                 :            : 
      70         [ #  # ]:          0 :   switch (property_id)
      71                 :            :     {
      72                 :          0 :     case PROP_SIZE_LIMIT:
      73                 :          0 :       g_value_set_uint (value, shumate_memory_cache_get_size_limit (memory_cache));
      74                 :          0 :       break;
      75                 :            : 
      76                 :          0 :     default:
      77                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      78                 :            :     }
      79                 :          0 : }
      80                 :            : 
      81                 :            : 
      82                 :            : static void
      83                 :         15 : shumate_memory_cache_set_property (GObject      *object,
      84                 :            :                                    guint         property_id,
      85                 :            :                                    const GValue *value,
      86                 :            :                                    GParamSpec   *pspec)
      87                 :            : {
      88                 :         15 :   ShumateMemoryCache *memory_cache = SHUMATE_MEMORY_CACHE (object);
      89                 :            : 
      90         [ +  - ]:         15 :   switch (property_id)
      91                 :            :     {
      92                 :         15 :     case PROP_SIZE_LIMIT:
      93                 :         15 :       shumate_memory_cache_set_size_limit (memory_cache, g_value_get_uint (value));
      94                 :         15 :       break;
      95                 :            : 
      96                 :          0 :     default:
      97                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      98                 :            :     }
      99                 :         15 : }
     100                 :            : 
     101                 :            : static void
     102                 :         15 : shumate_memory_cache_finalize (GObject *object)
     103                 :            : {
     104                 :         15 :   ShumateMemoryCache *self = SHUMATE_MEMORY_CACHE (object);
     105                 :            : 
     106                 :         15 :   shumate_memory_cache_clean (self);
     107         [ +  - ]:         15 :   g_clear_pointer (&self->queue, g_queue_free);
     108         [ +  - ]:         15 :   g_clear_pointer (&self->hash_table, g_hash_table_unref);
     109                 :            : 
     110                 :         15 :   G_OBJECT_CLASS (shumate_memory_cache_parent_class)->finalize (object);
     111                 :         15 : }
     112                 :            : 
     113                 :            : 
     114                 :            : static void
     115                 :          3 : shumate_memory_cache_class_init (ShumateMemoryCacheClass *klass)
     116                 :            : {
     117                 :          3 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     118                 :            : 
     119                 :          3 :   object_class->finalize = shumate_memory_cache_finalize;
     120                 :          3 :   object_class->get_property = shumate_memory_cache_get_property;
     121                 :          3 :   object_class->set_property = shumate_memory_cache_set_property;
     122                 :            : 
     123                 :          6 :   properties[PROP_SIZE_LIMIT] =
     124                 :          3 :     g_param_spec_uint ("size-limit",
     125                 :            :                        "Size Limit",
     126                 :            :                        "Maximal number of stored tiles",
     127                 :            :                        1,
     128                 :            :                        G_MAXINT,
     129                 :            :                        100,
     130                 :            :                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
     131                 :            : 
     132                 :          3 :   g_object_class_install_properties (object_class, N_PROPS, properties);
     133                 :          3 : }
     134                 :            : 
     135                 :            : 
     136                 :            : /**
     137                 :            :  * shumate_memory_cache_new_full:
     138                 :            :  * @size_limit: maximum number of tiles stored in the cache
     139                 :            :  *
     140                 :            :  * Constructor of #ShumateMemoryCache.
     141                 :            :  *
     142                 :            :  * Returns: a constructed #ShumateMemoryCache
     143                 :            :  */
     144                 :            : ShumateMemoryCache *
     145                 :         15 : shumate_memory_cache_new_full (guint size_limit)
     146                 :            : {
     147                 :         15 :   ShumateMemoryCache *cache;
     148                 :            : 
     149                 :         15 :   cache = g_object_new (SHUMATE_TYPE_MEMORY_CACHE,
     150                 :            :                         "size-limit", size_limit,
     151                 :            :                         NULL);
     152                 :            : 
     153                 :         15 :   return cache;
     154                 :            : }
     155                 :            : 
     156                 :            : 
     157                 :            : static void
     158                 :         15 : shumate_memory_cache_init (ShumateMemoryCache *self)
     159                 :            : {
     160                 :         15 :   self->queue = g_queue_new ();
     161                 :         15 :   self->hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
     162                 :         15 : }
     163                 :            : 
     164                 :            : 
     165                 :            : guint
     166                 :          0 : shumate_memory_cache_get_size_limit (ShumateMemoryCache *self)
     167                 :            : {
     168         [ #  # ]:          0 :   g_return_val_if_fail (SHUMATE_IS_MEMORY_CACHE (self), 0);
     169                 :            : 
     170                 :          0 :   return self->size_limit;
     171                 :            : }
     172                 :            : 
     173                 :            : 
     174                 :            : void
     175                 :         15 : shumate_memory_cache_set_size_limit (ShumateMemoryCache *self,
     176                 :            :                                      guint               size_limit)
     177                 :            : {
     178         [ +  - ]:         15 :   g_return_if_fail (SHUMATE_IS_MEMORY_CACHE (self));
     179                 :            : 
     180                 :         15 :   self->size_limit = size_limit;
     181                 :         15 :   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIZE_LIMIT]);
     182                 :            : }
     183                 :            : 
     184                 :            : 
     185                 :            : static char *
     186                 :         63 : generate_queue_key (ShumateMemoryCache *self,
     187                 :            :                     ShumateTile        *tile,
     188                 :            :                     const char         *source_id)
     189                 :            : {
     190         [ +  - ]:         63 :   g_return_val_if_fail (SHUMATE_IS_MEMORY_CACHE (self), NULL);
     191         [ -  + ]:         63 :   g_return_val_if_fail (SHUMATE_IS_TILE (tile), NULL);
     192                 :            : 
     193                 :         63 :   char *key;
     194                 :            : 
     195                 :         63 :   key = g_strdup_printf ("%d/%d/%d/%s",
     196                 :            :         shumate_tile_get_zoom_level (tile),
     197                 :            :         shumate_tile_get_x (tile),
     198                 :            :         shumate_tile_get_y (tile),
     199                 :            :         source_id);
     200                 :         63 :   return key;
     201                 :            : }
     202                 :            : 
     203                 :            : 
     204                 :            : static void
     205                 :         27 : move_queue_member_to_head (GQueue *queue, GList *link)
     206                 :            : {
     207                 :         27 :   g_queue_unlink (queue, link);
     208                 :         27 :   g_queue_push_head_link (queue, link);
     209                 :         27 : }
     210                 :            : 
     211                 :            : 
     212                 :            : static void
     213                 :         27 : delete_queue_member (QueueMember *member, gpointer user_data)
     214                 :            : {
     215         [ +  - ]:         27 :   if (member)
     216                 :            :     {
     217         [ +  + ]:         27 :       g_clear_object (&member->paintable);
     218         [ -  + ]:         27 :       g_clear_pointer (&member->symbols, g_ptr_array_unref);
     219         [ +  - ]:         27 :       g_clear_pointer (&member->key, g_free);
     220                 :         27 :       g_free (member);
     221                 :            :     }
     222                 :         27 : }
     223                 :            : 
     224                 :            : 
     225                 :            : void
     226                 :         18 : shumate_memory_cache_clean (ShumateMemoryCache *self)
     227                 :            : {
     228                 :         18 :   g_queue_foreach (self->queue, (GFunc) delete_queue_member, NULL);
     229                 :         18 :   g_queue_clear (self->queue);
     230                 :         18 :   g_hash_table_unref (self->hash_table);
     231                 :         18 :   self->hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
     232                 :         18 : }
     233                 :            : 
     234                 :            : 
     235                 :            : gboolean
     236                 :         36 : shumate_memory_cache_try_fill_tile (ShumateMemoryCache *self,
     237                 :            :                                     ShumateTile        *tile,
     238                 :            :                                     const char         *source_id)
     239                 :            : {
     240                 :         36 :   ShumateMemoryCache *memory_cache = (ShumateMemoryCache *) self;
     241                 :         36 :   GList *link;
     242                 :         36 :   QueueMember *member;
     243                 :         72 :   g_autofree char *key = NULL;
     244                 :            : 
     245         [ +  - ]:         36 :   g_return_val_if_fail (SHUMATE_IS_MEMORY_CACHE (self), FALSE);
     246         [ -  + ]:         36 :   g_return_val_if_fail (SHUMATE_IS_TILE (tile), FALSE);
     247                 :            : 
     248                 :         36 :   key = generate_queue_key (memory_cache, tile, source_id);
     249                 :            : 
     250                 :         36 :   link = g_hash_table_lookup (self->hash_table, key);
     251         [ +  + ]:         36 :   if (link == NULL)
     252                 :            :     return FALSE;
     253                 :            : 
     254                 :         27 :   member = link->data;
     255                 :            : 
     256                 :         27 :   move_queue_member_to_head (self->queue, link);
     257                 :            : 
     258                 :         27 :   shumate_tile_set_paintable (tile, member->paintable);
     259                 :         27 :   shumate_tile_set_symbols (tile, member->symbols);
     260                 :         27 :   shumate_tile_set_fade_in (tile, FALSE);
     261                 :         27 :   shumate_tile_set_state (tile, SHUMATE_STATE_DONE);
     262                 :         27 :   return TRUE;
     263                 :            : }
     264                 :            : 
     265                 :            : void
     266                 :         27 : shumate_memory_cache_store_tile (ShumateMemoryCache *self,
     267                 :            :                                  ShumateTile        *tile,
     268                 :            :                                  const char         *source_id)
     269                 :            : {
     270                 :         27 :   GList *link;
     271                 :         27 :   char *key;
     272                 :            : 
     273         [ +  - ]:         27 :   g_return_if_fail (SHUMATE_IS_MEMORY_CACHE (self));
     274         [ -  + ]:         27 :   g_return_if_fail (SHUMATE_IS_TILE (tile));
     275                 :            : 
     276                 :         27 :   key = generate_queue_key (self, tile, source_id);
     277                 :         27 :   link = g_hash_table_lookup (self->hash_table, key);
     278         [ -  + ]:         27 :   if (link)
     279                 :            :     {
     280                 :          0 :       move_queue_member_to_head (self->queue, link);
     281                 :          0 :       g_free (key);
     282                 :            :     }
     283                 :            :   else
     284                 :            :     {
     285                 :         27 :       QueueMember *member;
     286                 :         27 :       GdkPaintable *paintable;
     287                 :         27 :       GPtrArray *symbols;
     288                 :            : 
     289         [ +  + ]:         27 :       if (self->queue->length >= self->size_limit)
     290                 :            :         {
     291                 :          3 :           member = g_queue_pop_tail (self->queue);
     292                 :          3 :           g_hash_table_remove (self->hash_table, member->key);
     293                 :          3 :           delete_queue_member (member, NULL);
     294                 :            :         }
     295                 :            : 
     296                 :         27 :       member = g_new0 (QueueMember, 1);
     297                 :         27 :       member->key = key;
     298         [ +  + ]:         27 :       if ((paintable = shumate_tile_get_paintable (tile)))
     299                 :         12 :         member->paintable = g_object_ref (paintable);
     300         [ -  + ]:         27 :       if ((symbols = shumate_tile_get_symbols (tile)))
     301                 :          0 :         member->symbols = g_ptr_array_ref (symbols);
     302                 :            : 
     303                 :         27 :       g_queue_push_head (self->queue, member);
     304         [ -  + ]:         54 :       g_hash_table_insert (self->hash_table, g_strdup (key), g_queue_peek_head_link (self->queue));
     305                 :            :     }
     306                 :            : }

Generated by: LCOV version 1.14