dangerous but cool commit. Normal word cache.

This commit is contained in:
p.kosyh 2010-10-06 12:41:56 +00:00
parent f2aaf133fd
commit 29ad172896
4 changed files with 199 additions and 44 deletions

View file

@ -3,22 +3,52 @@
#include "list.h"
#include "cache.h"
#define HASH_SIZE 1023
typedef struct {
struct list_head list;
int size;
int max_size;
cache_free_fn free_fn;
struct list_head hash[HASH_SIZE];
struct list_head vhash[HASH_SIZE];
} __cache_t;
typedef struct {
struct list_head list;
struct list_head *hash;
struct list_head *vhash;
char *name;
void *data;
int free_it;
int used;
} __cache_e_t;
typedef struct {
struct list_head list;
struct list_head *data;
} __hash_item_t;
/* #define GOLDEN_RATIO_PRIME_32 0x9e370001UL */
#include <stdio.h>
static unsigned long hash_addr(void *p)
{
return (long)p;
}
static u_int32_t hash_string(const char *str)
{
u_int32_t hash = 0;
int i;
int len = strlen(str);
for (i = 0; i < len; i++) {
hash ^= str[i]; /* GOLDEN_RATIO_PRIME_32; */
hash = (hash << 11) | (hash >> 21);
}
return hash;
}
cache_t cache_init(int size, cache_free_fn free_fn)
{
int i = 0;
__cache_t *c = malloc(sizeof(__cache_t));
if (!c)
return NULL;
@ -26,6 +56,10 @@ cache_t cache_init(int size, cache_free_fn free_fn)
c->size = 0;
c->max_size = size;
c->free_fn = free_fn;
for (i = 0; i < HASH_SIZE; i++) {
INIT_LIST_HEAD(&c->hash[i]);
INIT_LIST_HEAD(&c->vhash[i]);
}
return (cache_t)c;
}
@ -35,8 +69,12 @@ static void cache_e_free(cache_t cache, __cache_e_t *cc)
if (!c)
return;
free(cc->name);
if (c->free_fn && cc->free_it)
if (c->free_fn && !cc->used)
c->free_fn(cc->data);
list_del(cc->hash);
free(cc->hash);
list_del(cc->vhash);
free(cc->vhash);
list_del((struct list_head*)cc);
free(cc);
}
@ -62,12 +100,14 @@ void cache_free(cache_t cache)
static __cache_e_t *cache_lookup(cache_t cache, const char *name)
{
struct list_head *pos;
struct list_head *list;
__cache_t *c = cache;
__cache_e_t *cc;
if (!c || !name)
return NULL;
list_for_each(pos, &c->list) {
cc = (__cache_e_t*) pos;
return NULL;
list = &c->hash[hash_string(name) % HASH_SIZE];
list_for_each(pos, list) {
cc = (__cache_e_t*)((__hash_item_t*)pos)->data;
if (!strcmp(cc->name, name))
return cc;
}
@ -77,23 +117,29 @@ static __cache_e_t *cache_lookup(cache_t cache, const char *name)
static __cache_e_t *cache_data(cache_t cache, void *p)
{
struct list_head *pos;
struct list_head *list;
__cache_t *c = cache;
__cache_e_t *cc;
if (!c || !p)
return NULL;
list_for_each(pos, &c->list) {
cc = (__cache_e_t*) pos;
list = &c->vhash[hash_addr(p) % HASH_SIZE];
list_for_each(pos, list) {
cc = (__cache_e_t*)((__hash_item_t*)pos)->data;
if (p == cc->data)
return cc;
}
return NULL;
}
void cache_forget(cache_t cache, void *p)
int cache_forget(cache_t cache, void *p)
{
__cache_e_t *cc = cache_data(cache, p);
if (cc)
cc->free_it = 1;
if (cc && cc->used) {
cc->used --;
return 0;
}
return -1;
}
void *cache_get(cache_t cache, const char *name)
@ -105,7 +151,7 @@ void *cache_get(cache_t cache, const char *name)
cc = cache_lookup(cache, name);
if (!cc)
return NULL;
cc->free_it = 0; /* need again! */
cc->used ++; /* need again! */
list_move((struct list_head*)cc, &c->list); /* first place */
// printf("%p\n", cc->data);
return cc->data;
@ -126,7 +172,10 @@ int cache_have(cache_t cache, void *p)
int cache_add(cache_t cache, const char *name, void *p)
{
__cache_e_t *cc;
__hash_item_t *hh;
__hash_item_t *vh;
__cache_t *c = cache;
struct list_head *list;
if (!c || !name)
return -1;
cc = cache_lookup(cache, name);
@ -135,20 +184,51 @@ int cache_add(cache_t cache, const char *name, void *p)
cc = malloc(sizeof(__cache_e_t));
if (!cc)
return -1;
hh = malloc(sizeof(__hash_item_t));
if (!hh) {
free(cc);
return -1;
}
vh = malloc(sizeof(__hash_item_t));
if (!vh) {
free(hh);
free(cc);
return -1;
}
cc->name = strdup(name);
if (!cc->name) {
free(vh);
free(hh);
free(cc);
return -1;
}
cc->data = p;
cc->free_it = 0;
cc->used = 1;
cc->hash = (struct list_head*) hh;
cc->vhash = (struct list_head*) vh;
list_add((struct list_head*)cc, &c->list);
list = &c->hash[hash_string(name) % HASH_SIZE];
hh->data = (struct list_head*)cc;
list_add((struct list_head*)hh, list);
list = &c->vhash[hash_addr(p) % HASH_SIZE];
vh->data = (struct list_head*)cc;
list_add((struct list_head*)vh, list);
c->size ++;
// printf("size: %d:%s\n", c->size, name);
if (c->size > c->max_size) {
c->size --;
cache_e_free(cache, (__cache_e_t *)c->list.prev);
while (c->size > c->max_size) {
__cache_e_t *cc;
cc = (__cache_e_t *)c->list.prev;
if (!cc->used) {
c->size --;
cache_e_free(cache, (__cache_e_t *)c->list.prev);
} else
break;
}
return 0;
}

View file

@ -6,7 +6,7 @@ typedef void (*cache_free_fn)(void *p);
extern cache_t cache_init(int size, cache_free_fn);
extern void cache_free(cache_t cache);
extern void cache_forget(cache_t cache, void *p);
extern int cache_forget(cache_t cache, void *p);
extern void cache_zap(cache_t cache);
extern void *cache_get(cache_t cache, const char *name);
extern int cache_add(cache_t cache, const char *name, void *p);

View file

@ -162,6 +162,7 @@ static struct {
{"yellowgreen", 0x9acd32},
{NULL, 0x0},
};
int gfx_parse_color (
const char *spec,
color_t *def)
@ -1236,22 +1237,6 @@ struct word *word_new(const char *str)
return w;
}
void word_free(struct word *word)
{
if (!word)
return;
// if (word->img)
// gfx_free_image(word->img);
if (word->word)
free(word->word);
if (word->prerend)
SDL_FreeSurface(word->prerend);
if (word->hlprerend)
SDL_FreeSurface(word->hlprerend);
word->hlprerend = word->prerend = NULL;
free(word);
}
struct line {
int y;
int h;
@ -1265,6 +1250,7 @@ struct line {
struct layout *layout;
};
int word_geom(word_t v, int *x, int *y, int *w, int *h)
{
int xx, yy, ww, hh;
@ -1389,6 +1375,8 @@ void line_align(struct line *line, int width, int style, int nl)
return line_right(line, width);
}
void word_free(struct word *word);
void line_free(struct line *line)
{
struct word *w;
@ -1474,6 +1462,8 @@ struct layout {
int scnt[4];
int lstyle;
cache_t img_cache;
cache_t prerend_cache;
cache_t hlprerend_cache;
};
struct word_list {
@ -1498,6 +1488,28 @@ struct textbox {
int h;
};
void word_free(struct word *word)
{
if (!word)
return;
// if (word->img)
// gfx_free_image(word->img);
if (word->word)
free(word->word);
if (word->prerend) {
cache_forget(word->line->layout->prerend_cache, word->prerend);
// SDL_FreeSurface(word->prerend);
}
if (word->hlprerend) {
cache_forget(word->line->layout->hlprerend_cache, word->hlprerend);
// SDL_FreeSurface(word->hlprerend);
}
word->hlprerend = word->prerend = NULL;
free(word);
}
struct xref *xref_new(char *link)
{
struct xref *p;
@ -1613,6 +1625,11 @@ void layout_add_xref(struct layout *layout, struct xref *xref)
return;
}
void sdl_surface_free(void *p)
{
SDL_FreeSurface(p);
}
struct layout *layout_new(fnt_t fn, int w, int h)
{
struct layout *l;
@ -1634,6 +1651,8 @@ struct layout *layout_new(fnt_t fn, int w, int h)
l->acol = gfx_col(255, 0, 0);
l->box = NULL;
l->img_cache = cache_init(GFX_CACHE_SIZE, gfx_free_image);
l->prerend_cache = cache_init(WORD_CACHE_SIZE, sdl_surface_free);
l->hlprerend_cache = cache_init(LINK_CACHE_SIZE, sdl_surface_free);
memset(l->scnt, 0, sizeof(l->scnt));
memset(l->saved_align, 0, sizeof(l->saved_align));
memset(l->saved_valign, 0, sizeof(l->saved_valign));
@ -1731,7 +1750,11 @@ void txt_layout_free(layout_t lay)
_txt_layout_free(lay);
if (lay) {
cache_free(layout->img_cache);
cache_free(layout->prerend_cache);
cache_free(layout->hlprerend_cache);
layout->img_cache = NULL;
layout->prerend_cache = NULL;
layout->hlprerend_cache = NULL;
free(lay);
}
}
@ -2068,37 +2091,86 @@ void txt_layout_link_style(layout_t lay, int style)
layout->lstyle = style;
}
static char *word_cache_string(struct word *w, u_int32_t style)
{
char *p;
int len = 0;
len = (w->word)?strlen(w->word):0;
len += 16;
p = malloc(len);
if (!p)
return NULL;
sprintf(p, "%s-%08x", (w->word)?w->word:"", style);
return p;
}
static void word_render(struct layout *layout, struct word *word, int x, int y)
{
char *wc = NULL;
SDL_Surface *s;
SDL_Surface *prerend = NULL;
SDL_Surface *hlprerend = NULL;
SDL_Color fgcol = { .r = layout->col.r, .g = layout->col.g, .b = layout->col.b };
SDL_Color lcol = { .r = layout->lcol.r, .g = layout->lcol.g, .b = layout->lcol.b };
SDL_Color acol = { .r = layout->acol.r, .g = layout->acol.g, .b = layout->acol.b };
u_int32_t style;
if (word->xref && !word->style)
if (!word->xref) {
style = (fgcol.r << 24) + (fgcol.g << 16) + (fgcol.b << 8);
} else if (word->xref->active) {
style = (acol.r << 24) + (acol.g << 16) + (acol.b << 8);
} else {
style = (lcol.r << 24) + (lcol.g << 16) + (lcol.b << 8);
}
if (word->xref && !word->style) {
TTF_SetFontStyle((TTF_Font *)(layout->fn), layout->lstyle);
else
wc = word_cache_string(word, layout->lstyle | style);
} else {
TTF_SetFontStyle((TTF_Font *)(layout->fn), word->style);
wc = word_cache_string(word, word->style | style);
}
if (!wc)
return;
if (!word->xref) {
if (!word->prerend) {
word->prerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, fgcol);
word->prerend = gfx_display_alpha(word->prerend);
prerend = cache_get(layout->prerend_cache, wc);
if (!prerend) {
word->prerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, fgcol);
word->prerend = gfx_display_alpha(word->prerend);
cache_add(layout->prerend_cache, wc, word->prerend);
} else {
word->prerend = prerend;
}
}
s = word->prerend;
} else if (word->xref->active) {
if (!word->hlprerend) {
word->hlprerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, acol);
word->hlprerend = gfx_display_alpha(word->hlprerend);
hlprerend = cache_get(layout->hlprerend_cache, wc);
if (!hlprerend) {
word->hlprerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, acol);
word->hlprerend = gfx_display_alpha(word->hlprerend);
cache_add(layout->hlprerend_cache, wc, word->hlprerend);
} else {
word->hlprerend = hlprerend;
}
}
s = word->hlprerend;
} else {
if (!word->prerend) {
word->prerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, lcol);
word->prerend = gfx_display_alpha(word->prerend);
prerend = cache_get(layout->prerend_cache, wc);
if (!prerend) {
word->prerend = TTF_RenderUTF8_Blended((TTF_Font *)(layout->fn), word->word, lcol);
word->prerend = gfx_display_alpha(word->prerend);
cache_add(layout->prerend_cache, wc, word->prerend);
} else {
word->prerend = prerend;
}
}
s = word->prerend;
}
free(wc);
if (!s)
return;
gfx_draw(s, x, y);
@ -3195,7 +3267,7 @@ int gfx_init(void)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
return -1;
}
}
return 0;
}

View file

@ -1,10 +1,13 @@
#ifndef __GRAPHICS_H__
#define __GRAPHICS_H__
#define GFX_CACHE_SIZE 32
#define GFX_CACHE_SIZE 64
#define GFX_MAX_CACHED_W 256
#define GFX_MAX_CACHED_H 256
#define WORD_CACHE_SIZE 1024
#define LINK_CACHE_SIZE 64
typedef void* gtimer_t;
typedef void* img_t;
typedef void* fnt_t;