Procházení všemi prvky keše
Funkce typu „foreach“ jsou všem pravidelným čtenářům jistě dobře známy. Stejný nástroj je implementován i do keší.
void g_cache_key_foreach(GCache *cache, GHFunc func, gpointer user_data); void (*GHFunc) (gpointer key, gpointer value, gpointer user_data);
Tato funkce zavolá na každý klíč keše cache
uživatelskou funkci func
a předá jí kromě klíče a sdílených dat i pointer user_data
. Jak jste si určitě všimli, funkce func
je typu GHFunc
, který už známe z dřívějška, konkrétně z kapitoly o hash-tabulkách.
Pro procházení keší je zde ale i jiná funkce:
void g_cache_value_foreach(GCache *cache, GHFunc func, gpointer user_data);
Její použití bych si ale dovolil nedoporučovat. Pokud jsem správně pochopil zdrojový kód knihovny, funkce g_cache_value_foreach()
prochází všemi prvky keše cache
a volá na ně uživatelskou funkci func
(která je rovněž typu GHFunc
). Této funkci ale jako klíč ( key
) předává pointer na sdílená data a jako hodnotu ( value
) ukazatel na speciální vnitřní datový typ, ke kterému by uživatel knihovny správně neměl mít vůbec přístup! Uživateli je tato datová položka naprosto k ničemu a proto se mi zdá tento přístup poněkud matoucí a nebezpečný. Patrně se tvůrcům GLib tato funkce nechtěně zatoulala do veřejné části rozhraní. Uděláte jenom dobře, budete-li ji ignorovat. (Jestli se pletu, tak mě opravte!!! :-)
A to je z rozhraní mechanizmu GCache
vše. Pojďme rychle na nějaký konkrétní příklad…
Příklad:
#include <glib.h>
/* nase struktura definujici jednu texturu */
typedef struct {
char *name; /* nazev textury */
int transparency; /* pruhlednost */
int array[200*200]; /* samotna textura */
} Texture;
/* funkce pro duplikaci klice */
static gpointer dup_key(gpointer key) {
return (gpointer) g_strdup((gchar *) key);
}
/* vytvoreni textury podle klice (nahrani z disku) */
static gpointer load_texture(gpointer key) {
Texture *t;
printf("Nacitam texturu %s ", key);
/* inicializace */
t = g_new0(Texture, 1);
t->name = (char *) dup_key(key);
/* skutecne nacteni je pro jednoduchost vypusteno */
}
/* HLAVNI PROGRAM */
gint main(void) {
GCache *textures; /* cache */
Texture *obj[10]; /* pole objektu */
Texture *mramor; /* jedna textura */
int x; /* pomocna promenna */
/* vytvoreni nove cache */
textures = g_cache_new(load_texture, g_free, dup_key,
g_free, g_str_hash, g_direct_hash, g_str_equal);
/* inicializace pole objektu */
obj[0] = g_cache_insert(textures, "Mramor");
obj[1] = g_cache_insert(textures, "Plast");
obj[2] = g_cache_insert(textures, "Mramor");
obj[3] = g_cache_insert(textures, "Drevo");
obj[4] = g_cache_insert(textures, "Drevo");
obj[5] = g_cache_insert(textures, "Mramor");
obj[6] = g_cache_insert(textures, "Kov");
obj[7] = g_cache_insert(textures, "Plast");
obj[8] = g_cache_insert(textures, "Drevo");
obj[9] = g_cache_insert(textures, "Mramor");
/* kontrolni vypis */
puts("");
for (x = 0; x < 10; x++) {
printf("obj[%d]: %s, %d ", x,
obj[x]->name, obj[x]->transparency);
}
/* editace jedne z textur */
mramor = g_cache_insert(textures,
"Mramor"); /* nacteni */
mramor->transparency = 255; /* editace */
g_cache_remove(textures, mramor); /* uvolneni */
/* kontrolni vypis */
puts("");
for (x = 0; x < 10; x++) {
printf("obj[%d]: %s, %d ", x,
obj[x]->name, obj[x]->transparency);
}
/* dealokace objektu (uvolneni textur) */
for (x = 0; x < 10; x++) {
g_cache_remove(textures, obj[x]);
}
/* dealokace cache */
g_cache_destroy(textures);
}
Výše uvedený příklad prosím chápejte jako nástin části kódu jakéhosi grafického programu, který na různé geometrické objekty aplikuje textury. V ukázce se definuje struktura Texture
, která slouží k uložení informací o texturách a právě ona bude předmětem kešování. Jejími prvky je jméno textury ( name
), průhlednost ( transparency
) a pole bajtů uchovávající samotnou texturu ( array
).
Klíčem textur bude řetězec – název.
Kromě hlavní funkce jsou v programu ještě dvě rutiny. Obě slouží pro účely mechanizmu kešování:
Funkce dup_key()
slouží pro duplikaci klíče a bude se předávat funkci g_cache_new()
jako parametr key_dup_func
.
Stejně tak funkce load_texture()
. I ona bude volána výhradně z vnitřku mechanizmu kešování. Funkci g_cache_new()
se bude předávat jako argument value_new_func
a jejím účelem je vytvořit nový záznam o textuře; načíst texturu z disku do datové struktury Texture
. Pro jednoduchost je však kód obstarávající načtení ze souboru vypuštěn.
Hlavní program obsahuje proměnnou textures
, což je samotná keš, pole obj
, které klidně chápejte jako jakési pole geometrických objektů (pro jednoduchost jsou v poli uloženy jen záznamy o texturách objektů), a pomocné proměnné mramor
a x
.
Po inicializaci keše textures
se inicializuje i pole objektů obj
. Z kontrolního výstupu můžete sledovat, že každý druh textury se opravdu inicializuje (načítá z disku) jen jednou.
Následuje editace atributů textury „Mramor“. Nejprve se do proměnné mramor
uloží voláním g_cache_insert()
pointer na záznam v keši, poté se položka modifikuje a nakonec se pointer keši zase vrátí ( g_cache_remove()
). Je důležité nezapomínat každý „získaný“ pointer zase „vracet“!
Po kontrolním výpisu se už jen uvolní z paměti všechny objekty a nakonec i samotná keš.
Výstupem programu by mělo být:
Nacitam texturu Mramor
Nacitam texturu Plast
Nacitam texturu Drevo
Nacitam texturu Kov
obj[0]: Mramor, 0
obj[1]: Plast, 0
obj[2]: Mramor, 0
obj[3]: Drevo, 0
obj[4]: Drevo, 0
obj[5]: Mramor, 0
obj[6]: Kov, 0
obj[7]: Plast, 0
obj[8]: Drevo, 0
obj[9]: Mramor, 0
obj[0]: Mramor, 255
obj[1]: Plast, 0
obj[2]: Mramor, 255
obj[3]: Drevo, 0
obj[4]: Drevo, 0
obj[5]: Mramor, 255
obj[6]: Kov, 0
obj[7]: Plast, 0
obj[8]: Drevo, 0
obj[9]: Mramor, 255
Co si z příkladu odnést? Možná to, že na funkce g_cache_insert()
a g_cache_remove()
je dobré pohlížet jako na dvojici funkcí g_malloc()
a g_free()
: každý ukazatel, který funkcí g_cache_insert()
získáme, je velice vhodné (!) po použití „rádoby-dealokovat“ voláním g_cache_remove()
. Jen tak si mechanizmus GCache
udrží pravdivý údaj o počtu ukazatelů na sdílená data a jen tak dosáhneme správné funkce celého systému kešování a úspory paměti.
Toť pro dnešek z mé strany vše. U dalšího pokračování se těší