]> git.street.me.uk Git - andy/viking.git/blame - src/mapcache.c
Fix a crash bug in mapcache reported by Jocelyn <jocelyn.jaubert@gmail.com>
[andy/viking.git] / src / mapcache.c
CommitLineData
50a14534
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <gtk/gtk.h>
23#include <string.h>
24#include "mapcache.h"
25
26#include "config.h"
27
28typedef struct _List {
29 struct _List *next;
30 gchar *key;
31} List;
32
33/* a circular linked list, a pointer to the tail, and the tail points to the head */
34/* this is so we can free the last */
35static List *queue_tail = NULL;
36static int queue_count = 0;
37
50a14534
EB
38static guint32 queue_size = 0;
39
40
41static GHashTable *cache = NULL;
42
43#define HASHKEY_FORMAT_STRING "%d-%d-%d-%d-%d-%d-%.3f-%.3f"
1fe49af0 44#define HASHKEY_FORMAT_STRING_NOSHRINK_NOR_ALPHA "%d-%d-%d-%d-%d-"
50a14534
EB
45
46void a_mapcache_init ()
47{
48 cache = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, g_object_unref );
49}
50
fd4536cf
QT
51static void cache_add(gchar *key, GdkPixbuf *pixbuf)
52{
53 /* TODO: Check if already exists */
54 g_hash_table_insert ( cache, key, pixbuf );
55 queue_size += gdk_pixbuf_get_rowstride(pixbuf) * gdk_pixbuf_get_height(pixbuf);
56 queue_size += 100;
57 queue_count++;
58}
59
60static void cache_remove(const gchar *key)
61{
62 GdkPixbuf *buf = g_hash_table_lookup ( cache, key );
63 if (buf) {
64 queue_size -= gdk_pixbuf_get_rowstride(buf) * gdk_pixbuf_get_height(buf);
65 queue_size -= 100;
66 queue_count --;
67 g_hash_table_remove ( cache, key );
68 }
69}
70
50a14534
EB
71/* returns key from head, adds on newtailkey to tail. */
72static gchar *list_shift_add_entry ( gchar *newtailkey )
73{
74 gchar *oldheadkey = queue_tail->next->key;
75 queue_tail->next->key = newtailkey;
76 queue_tail = queue_tail->next;
77 return oldheadkey;
78}
79
80static gchar *list_shift ()
81{
82 gchar *oldheadkey = queue_tail->next->key;
83 List *oldhead = queue_tail->next;
84 queue_tail->next = queue_tail->next->next;
85 g_free ( oldhead );
86 return oldheadkey;
87}
88
89/* adds key to tail */
90static void list_add_entry ( gchar *key )
91{
92 List *newlist = g_malloc ( sizeof ( List ) );
93 newlist->key = key;
94 if ( queue_tail ) {
95 newlist->next = queue_tail->next;
96 queue_tail->next = newlist;
97 queue_tail = newlist;
98 } else {
99 newlist->next = newlist;
100 queue_tail = newlist;
101 }
102}
103
104void a_mapcache_add ( GdkPixbuf *pixbuf, gint x, gint y, gint z, guint8 type, guint zoom, guint8 alpha, gdouble xshrinkfactor, gdouble yshrinkfactor )
105{
106 gchar *key = g_strdup_printf ( HASHKEY_FORMAT_STRING, x, y, z, type, zoom, alpha, xshrinkfactor, yshrinkfactor );
107 static int tmp = 0;
108
fd4536cf 109 cache_add(key, pixbuf);
50a14534
EB
110
111 if ( queue_size > VIK_CONFIG_MAPCACHE_SIZE ) {
112 gchar *oldkey = list_shift_add_entry ( key );
fd4536cf 113 cache_remove(oldkey);
1fe49af0 114
725c87e1
EB
115 while ( queue_size > VIK_CONFIG_MAPCACHE_SIZE &&
116 (queue_tail->next != queue_tail) ) { /* make sure there's more than one thing to delete */
50a14534 117 oldkey = list_shift ();
fd4536cf 118 cache_remove(oldkey);
50a14534
EB
119 }
120
121 /* chop off 'start' etc */
122 } else {
123 list_add_entry ( key );
124 /* business as usual */
125 }
126
494eb388 127 if ( (++tmp == 100 )) { g_print("DEBUG: queue count=%d %u\n", queue_count, queue_size ); tmp=0; }
50a14534
EB
128}
129
130GdkPixbuf *a_mapcache_get ( gint x, gint y, gint z, guint8 type, guint zoom, guint8 alpha, gdouble xshrinkfactor, gdouble yshrinkfactor )
131{
132 static char key[48];
133 g_snprintf ( key, sizeof(key), HASHKEY_FORMAT_STRING, x, y, z, type, zoom, alpha, xshrinkfactor, yshrinkfactor );
134 return g_hash_table_lookup ( cache, key );
135}
136
e044ae9e 137void a_mapcache_remove_all_shrinkfactors ( gint x, gint y, gint z, guint8 type, guint zoom )
50a14534
EB
138{
139 char key[40];
140 List *loop = queue_tail;
141 List *tmp;
142 gint len;
143
144 if ( queue_tail == NULL )
145 return;
146
1fe49af0 147 g_snprintf ( key, sizeof(key), HASHKEY_FORMAT_STRING_NOSHRINK_NOR_ALPHA, x, y, z, type, zoom );
50a14534
EB
148 len = strlen(key);
149
150 /* TODO: check logic here */
151 do {
152 tmp = loop->next;
153 if ( strncmp(tmp->key, key, len) == 0 )
154 {
fd4536cf 155 cache_remove(tmp->key);
093c5c71 156 if ( tmp == loop ) /* we deleted the last thing in the queue! */
50a14534 157 loop = queue_tail = NULL;
093c5c71 158 else {
50a14534 159 loop->next = tmp->next;
093c5c71
EB
160 if ( tmp == queue_tail )
161 queue_tail = tmp->next;
162 }
50a14534
EB
163 g_free ( tmp );
164 tmp = NULL;
165 }
166 else
167 loop = tmp;
168
169 } while ( loop && (loop != queue_tail || tmp == NULL) );
170
171 /* loop thru list, looking for the one, compare first whatever chars */
fd4536cf 172 cache_remove(key);
50a14534
EB
173}
174
175void a_mapcache_uninit ()
176{
177 g_hash_table_destroy ( cache );
178 /* free list */
179 cache = NULL;
180}
181
182