dangerous but cool commit. Normal word cache.
This commit is contained in:
parent
f2aaf133fd
commit
29ad172896
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Reference in a new issue