GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 85.5% 100 / 0 / 117
Functions: 88.2% 15 / 0 / 17
Branches: 53.7% 29 / 0 / 54

shumate/shumate-memory-cache.c
Line Branch Exec Source
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
4/6
shumate_memory_cache_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
shumate_memory_cache_get_type:
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 7 taken 102 times.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 7 not taken.
108 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 ✗ shumate_memory_cache_get_property (GObject *object,
64 guint property_id,
65 GValue *value,
66 GParamSpec *pspec)
67 {
68 ✗ ShumateMemoryCache *memory_cache = SHUMATE_MEMORY_CACHE (object);
69
70 ✗ switch (property_id)
71 {
72 ✗ case PROP_SIZE_LIMIT:
73 ✗ g_value_set_uint (value, shumate_memory_cache_get_size_limit (memory_cache));
74 ✗ break;
75
76 ✗ default:
77 ✗ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
78 }
79 ✗ }
80
81
82 static void
83 10 shumate_memory_cache_set_property (GObject *object,
84 guint property_id,
85 const GValue *value,
86 GParamSpec *pspec)
87 {
88 10 ShumateMemoryCache *memory_cache = SHUMATE_MEMORY_CACHE (object);
89
90
1/2
✓ Branch 2 → 3 taken 10 times.
✗ Branch 2 → 6 not taken.
10 switch (property_id)
91 {
92 10 case PROP_SIZE_LIMIT:
93 10 shumate_memory_cache_set_size_limit (memory_cache, g_value_get_uint (value));
94 10 break;
95
96 ✗ default:
97 ✗ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
98 }
99 10 }
100
101 static void
102 10 shumate_memory_cache_finalize (GObject *object)
103 {
104 10 ShumateMemoryCache *self = SHUMATE_MEMORY_CACHE (object);
105
106 10 shumate_memory_cache_clean (self);
107
1/2
✓ Branch 3 → 4 taken 10 times.
✗ Branch 3 → 5 not taken.
10 g_clear_pointer (&self->queue, g_queue_free);
108
1/2
✓ Branch 5 → 6 taken 10 times.
✗ Branch 5 → 7 not taken.
10 g_clear_pointer (&self->hash_table, g_hash_table_unref);
109
110 10 G_OBJECT_CLASS (shumate_memory_cache_parent_class)->finalize (object);
111 10 }
112
113
114 static void
115 2 shumate_memory_cache_class_init (ShumateMemoryCacheClass *klass)
116 {
117 2 GObjectClass *object_class = G_OBJECT_CLASS (klass);
118
119 2 object_class->finalize = shumate_memory_cache_finalize;
120 2 object_class->get_property = shumate_memory_cache_get_property;
121 2 object_class->set_property = shumate_memory_cache_set_property;
122
123 /**
124 * ShumateMemoryCache:size-limit:
125 *
126 * The maximal number of stored tiles
127 */
128 4 properties[PROP_SIZE_LIMIT] =
129 2 g_param_spec_uint ("size-limit", NULL, NULL,
130 1,
131 G_MAXINT,
132 100,
133 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
134
135 2 g_object_class_install_properties (object_class, N_PROPS, properties);
136 2 }
137
138
139 /**
140 * shumate_memory_cache_new_full:
141 * @size_limit: maximum number of tiles stored in the cache
142 *
143 * Constructor of #ShumateMemoryCache.
144 *
145 * Returns: a constructed #ShumateMemoryCache
146 */
147 ShumateMemoryCache *
148 10 shumate_memory_cache_new_full (guint size_limit)
149 {
150 10 ShumateMemoryCache *cache;
151
152 10 cache = g_object_new (SHUMATE_TYPE_MEMORY_CACHE,
153 "size-limit", size_limit,
154 NULL);
155
156 10 return cache;
157 }
158
159
160 static void
161 10 shumate_memory_cache_init (ShumateMemoryCache *self)
162 {
163 10 self->queue = g_queue_new ();
164 10 self->hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
165 10 }
166
167
168 guint
169 ✗ shumate_memory_cache_get_size_limit (ShumateMemoryCache *self)
170 {
171 ✗ g_return_val_if_fail (SHUMATE_IS_MEMORY_CACHE (self), 0);
172
173 ✗ return self->size_limit;
174 }
175
176
177 void
178 10 shumate_memory_cache_set_size_limit (ShumateMemoryCache *self,
179 guint size_limit)
180 {
181
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 10 times.
10 g_return_if_fail (SHUMATE_IS_MEMORY_CACHE (self));
182
183 10 self->size_limit = size_limit;
184 10 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIZE_LIMIT]);
185 }
186
187
188 static char *
189 42 generate_queue_key (ShumateMemoryCache *self,
190 ShumateTile *tile,
191 const char *source_id)
192 {
193
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 42 times.
42 g_return_val_if_fail (SHUMATE_IS_MEMORY_CACHE (self), NULL);
194
1/2
✓ Branch 6 → 7 taken 42 times.
✗ Branch 6 → 12 not taken.
42 g_return_val_if_fail (SHUMATE_IS_TILE (tile), NULL);
195
196 42 char *key;
197
198 42 key = g_strdup_printf ("%d/%d/%d/%s",
199 shumate_tile_get_zoom_level (tile),
200 shumate_tile_get_x (tile),
201 shumate_tile_get_y (tile),
202 source_id);
203 42 return key;
204 }
205
206
207 static void
208 18 move_queue_member_to_head (GQueue *queue, GList *link)
209 {
210 18 g_queue_unlink (queue, link);
211 18 g_queue_push_head_link (queue, link);
212 18 }
213
214
215 static void
216 18 delete_queue_member (QueueMember *member, gpointer user_data)
217 {
218
1/2
✓ Branch 2 → 3 taken 18 times.
✗ Branch 2 → 12 not taken.
18 if (member)
219 {
220
2/2
✓ Branch 3 → 4 taken 8 times.
✓ Branch 3 → 5 taken 10 times.
18 g_clear_object (&member->paintable);
221
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 18 times.
18 g_clear_pointer (&member->symbols, g_ptr_array_unref);
222
1/2
✓ Branch 7 → 8 taken 18 times.
✗ Branch 7 → 9 not taken.
18 g_clear_pointer (&member->key, g_free);
223
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 18 times.
18 g_free (member);
224 }
225 18 }
226
227
228 void
229 12 shumate_memory_cache_clean (ShumateMemoryCache *self)
230 {
231 12 g_queue_foreach (self->queue, (GFunc) delete_queue_member, NULL);
232 12 g_queue_clear (self->queue);
233 12 g_hash_table_unref (self->hash_table);
234 12 self->hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
235 12 }
236
237
238 gboolean
239 24 shumate_memory_cache_try_fill_tile (ShumateMemoryCache *self,
240 ShumateTile *tile,
241 const char *source_id)
242 {
243 24 ShumateMemoryCache *memory_cache = (ShumateMemoryCache *) self;
244 24 GList *link;
245 24 QueueMember *member;
246 24 g_autofree char *key = NULL;
247
248
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 24 times.
24 g_return_val_if_fail (SHUMATE_IS_MEMORY_CACHE (self), FALSE);
249
1/2
✓ Branch 6 → 7 taken 24 times.
✗ Branch 6 → 10 not taken.
24 g_return_val_if_fail (SHUMATE_IS_TILE (tile), FALSE);
250
251 24 key = generate_queue_key (memory_cache, tile, source_id);
252
253 24 link = g_hash_table_lookup (self->hash_table, key);
254
2/2
✓ Branch 9 → 11 taken 18 times.
✓ Branch 9 → 17 taken 6 times.
24 if (link == NULL)
255 return FALSE;
256
257 18 member = link->data;
258
259 18 move_queue_member_to_head (self->queue, link);
260
261 18 shumate_tile_set_symbols (tile, member->symbols);
262 18 shumate_tile_set_paintable (tile, member->paintable);
263 18 shumate_tile_set_fade_in (tile, FALSE);
264 18 shumate_tile_set_state (tile, SHUMATE_STATE_DONE);
265 18 return TRUE;
266 }
267
268 void
269 18 shumate_memory_cache_store_tile (ShumateMemoryCache *self,
270 ShumateTile *tile,
271 const char *source_id)
272 {
273 18 GList *link;
274 18 char *key;
275
276
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 18 times.
18 g_return_if_fail (SHUMATE_IS_MEMORY_CACHE (self));
277
1/2
✓ Branch 6 → 7 taken 18 times.
✗ Branch 6 → 10 not taken.
18 g_return_if_fail (SHUMATE_IS_TILE (tile));
278
279 18 key = generate_queue_key (self, tile, source_id);
280 18 link = g_hash_table_lookup (self->hash_table, key);
281
1/2
✗ Branch 9 → 11 not taken.
✓ Branch 9 → 15 taken 18 times.
18 if (link)
282 {
283 ✗ move_queue_member_to_head (self->queue, link);
284 ✗ g_free (key);
285 }
286 else
287 {
288 18 QueueMember *member;
289 18 GdkPaintable *paintable;
290 18 GPtrArray *symbols;
291
292
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 19 taken 16 times.
18 if (self->queue->length >= self->size_limit)
293 {
294 2 member = g_queue_pop_tail (self->queue);
295 2 g_hash_table_remove (self->hash_table, member->key);
296 2 delete_queue_member (member, NULL);
297 }
298
299 18 member = g_new0 (QueueMember, 1);
300 18 member->key = key;
301
2/2
✓ Branch 21 → 22 taken 8 times.
✓ Branch 21 → 24 taken 10 times.
18 if ((paintable = shumate_tile_get_paintable (tile)))
302 8 member->paintable = g_object_ref (paintable);
303
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 28 taken 18 times.
18 if ((symbols = shumate_tile_get_symbols (tile)))
304 ✗ member->symbols = g_ptr_array_ref (symbols);
305
306 18 g_queue_push_head (self->queue, member);
307
1/2
✗ Branch 30 → 31 not taken.
✓ Branch 30 → 32 taken 18 times.
36 g_hash_table_insert (self->hash_table, g_strdup (key), g_queue_peek_head_link (self->queue));
308 }
309 }
310