2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
3 * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
5 * This file is part of libass.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 #include "ass_utils.h"
29 #include "ass_cache.h"
31 // type-specific functions
32 // create hash/compare functions for bitmap, outline and composite cache
33 #define CREATE_HASH_FUNCTIONS
34 #include "ass_cache_template.h"
35 #define CREATE_COMPARISON_FUNCTIONS
36 #include "ass_cache_template.h"
39 static unsigned font_hash(void *buf
, size_t len
)
41 ASS_FontDesc
*desc
= buf
;
43 hval
= fnv_32a_str(desc
->family
, FNV1_32A_INIT
);
44 hval
= fnv_32a_buf(&desc
->bold
, sizeof(desc
->bold
), hval
);
45 hval
= fnv_32a_buf(&desc
->italic
, sizeof(desc
->italic
), hval
);
46 hval
= fnv_32a_buf(&desc
->treat_family_as_pattern
,
47 sizeof(desc
->treat_family_as_pattern
), hval
);
48 hval
= fnv_32a_buf(&desc
->vertical
, sizeof(desc
->vertical
), hval
);
52 static unsigned font_compare(void *key1
, void *key2
, size_t key_size
)
54 ASS_FontDesc
*a
= key1
;
55 ASS_FontDesc
*b
= key2
;
56 if (strcmp(a
->family
, b
->family
) != 0)
58 if (a
->bold
!= b
->bold
)
60 if (a
->italic
!= b
->italic
)
62 if (a
->treat_family_as_pattern
!= b
->treat_family_as_pattern
)
64 if (a
->vertical
!= b
->vertical
)
69 static void font_destruct(void *key
, void *value
)
76 static void bitmap_destruct(void *key
, void *value
)
78 BitmapHashValue
*v
= value
;
79 BitmapHashKey
*k
= key
;
81 ass_free_bitmap(v
->bm
);
83 ass_free_bitmap(v
->bm_o
);
85 ass_free_bitmap(v
->bm_s
);
86 if (k
->type
== BITMAP_CLIP
)
92 static size_t bitmap_size(void *value
, size_t value_size
)
94 BitmapHashValue
*val
= value
;
96 return val
->bm_o
->w
* val
->bm_o
->h
* 3;
98 return val
->bm
->w
* val
->bm
->h
* 3;
102 static unsigned bitmap_hash(void *key
, size_t key_size
)
104 BitmapHashKey
*k
= key
;
106 case BITMAP_OUTLINE
: return outline_bitmap_hash(&k
->u
, key_size
);
107 case BITMAP_CLIP
: return clip_bitmap_hash(&k
->u
, key_size
);
112 static unsigned bitmap_compare (void *a
, void *b
, size_t key_size
)
114 BitmapHashKey
*ak
= a
;
115 BitmapHashKey
*bk
= b
;
116 if (ak
->type
!= bk
->type
) return 0;
118 case BITMAP_OUTLINE
: return outline_bitmap_compare(&ak
->u
, &bk
->u
, key_size
);
119 case BITMAP_CLIP
: return clip_bitmap_compare(&ak
->u
, &bk
->u
, key_size
);
125 static void composite_destruct(void *key
, void *value
)
127 CompositeHashValue
*v
= value
;
136 static unsigned outline_hash(void *key
, size_t key_size
)
138 OutlineHashKey
*k
= key
;
140 case OUTLINE_GLYPH
: return glyph_hash(&k
->u
, key_size
);
141 case OUTLINE_DRAWING
: return drawing_hash(&k
->u
, key_size
);
146 static unsigned outline_compare(void *a
, void *b
, size_t key_size
)
148 OutlineHashKey
*ak
= a
;
149 OutlineHashKey
*bk
= b
;
150 if (ak
->type
!= bk
->type
) return 0;
152 case OUTLINE_GLYPH
: return glyph_compare(&ak
->u
, &bk
->u
, key_size
);
153 case OUTLINE_DRAWING
: return drawing_compare(&ak
->u
, &bk
->u
, key_size
);
158 static void outline_destruct(void *key
, void *value
)
160 OutlineHashValue
*v
= value
;
161 OutlineHashKey
*k
= key
;
163 outline_free(v
->lib
, v
->outline
);
165 outline_free(v
->lib
, v
->border
);
166 if (k
->type
== OUTLINE_DRAWING
)
167 free(k
->u
.drawing
.text
);
175 typedef struct cache_item
{
178 struct cache_item
*next
;
185 HashFunction hash_func
;
187 HashCompare compare_func
;
188 CacheItemDestructor destruct_func
;
198 // Hash for a simple (single value or array) type
199 static unsigned hash_simple(void *key
, size_t key_size
)
201 return fnv_32a_buf(key
, key_size
, FNV1_32A_INIT
);
204 // Comparison of a simple type
205 static unsigned compare_simple(void *a
, void *b
, size_t key_size
)
207 return memcmp(a
, b
, key_size
) == 0;
210 // Default destructor
211 static void destruct_simple(void *key
, void *value
)
218 // Create a cache with type-specific hash/compare/destruct/size functions
219 Cache
*ass_cache_create(HashFunction hash_func
, HashCompare compare_func
,
220 CacheItemDestructor destruct_func
, ItemSize size_func
,
221 size_t key_size
, size_t value_size
)
223 Cache
*cache
= calloc(1, sizeof(*cache
));
224 cache
->buckets
= 0xFFFF;
225 cache
->hash_func
= hash_simple
;
226 cache
->compare_func
= compare_simple
;
227 cache
->destruct_func
= destruct_simple
;
228 cache
->size_func
= size_func
;
230 cache
->hash_func
= hash_func
;
232 cache
->compare_func
= compare_func
;
234 cache
->destruct_func
= destruct_func
;
235 cache
->key_size
= key_size
;
236 cache
->value_size
= value_size
;
237 cache
->map
= calloc(cache
->buckets
, sizeof(CacheItem
*));
242 void *ass_cache_put(Cache
*cache
, void *key
, void *value
)
244 unsigned bucket
= cache
->hash_func(key
, cache
->key_size
) % cache
->buckets
;
245 CacheItem
**item
= &cache
->map
[bucket
];
247 item
= &(*item
)->next
;
248 (*item
) = calloc(1, sizeof(CacheItem
));
249 (*item
)->key
= malloc(cache
->key_size
);
250 (*item
)->value
= malloc(cache
->value_size
);
251 memcpy((*item
)->key
, key
, cache
->key_size
);
252 memcpy((*item
)->value
, value
, cache
->value_size
);
255 if (cache
->size_func
)
256 cache
->cache_size
+= cache
->size_func(value
, cache
->value_size
);
260 return (*item
)->value
;
263 void *ass_cache_get(Cache
*cache
, void *key
)
265 unsigned bucket
= cache
->hash_func(key
, cache
->key_size
) % cache
->buckets
;
266 CacheItem
*item
= cache
->map
[bucket
];
268 if (cache
->compare_func(key
, item
->key
, cache
->key_size
)) {
278 int ass_cache_empty(Cache
*cache
, size_t max_size
)
282 if (cache
->cache_size
< max_size
)
285 for (i
= 0; i
< cache
->buckets
; i
++) {
286 CacheItem
*item
= cache
->map
[i
];
288 CacheItem
*next
= item
->next
;
289 cache
->destruct_func(item
->key
, item
->value
);
293 cache
->map
[i
] = NULL
;
296 cache
->items
= cache
->hits
= cache
->misses
= cache
->cache_size
= 0;
301 void ass_cache_stats(Cache
*cache
, size_t *size
, unsigned *hits
,
302 unsigned *misses
, unsigned *count
)
305 *size
= cache
->cache_size
;
309 *misses
= cache
->misses
;
311 *count
= cache
->items
;
314 void ass_cache_done(Cache
*cache
)
316 ass_cache_empty(cache
, 0);
321 // Type-specific creation function
322 Cache
*ass_font_cache_create(void)
324 return ass_cache_create(font_hash
, font_compare
, font_destruct
,
325 (ItemSize
)NULL
, sizeof(ASS_FontDesc
), sizeof(ASS_Font
));
328 Cache
*ass_outline_cache_create(void)
330 return ass_cache_create(outline_hash
, outline_compare
, outline_destruct
,
331 NULL
, sizeof(OutlineHashKey
), sizeof(OutlineHashValue
));
334 Cache
*ass_glyph_metrics_cache_create(void)
336 return ass_cache_create(glyph_metrics_hash
, glyph_metrics_compare
, NULL
,
337 (ItemSize
) NULL
, sizeof(GlyphMetricsHashKey
),
338 sizeof(GlyphMetricsHashValue
));
341 Cache
*ass_bitmap_cache_create(void)
343 return ass_cache_create(bitmap_hash
, bitmap_compare
, bitmap_destruct
,
344 bitmap_size
, sizeof(BitmapHashKey
), sizeof(BitmapHashValue
));
347 Cache
*ass_composite_cache_create(void)
349 return ass_cache_create(composite_hash
, composite_compare
,
350 composite_destruct
, (ItemSize
)NULL
, sizeof(CompositeHashKey
),
351 sizeof(CompositeHashValue
));