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