@ -23,6 +23,21 @@
# include "ftcerror.h"
/* define for level-1 optimisations */
# undef OPT1
# ifdef FTC_CACHE_USE_LINEAR_HASHING
# define FTC_HASH_MAX_LOAD 2
# define FTC_HASH_MIN_LOAD 1
# define FTC_HASH_SUB_LOAD (FTC_HASH_MAX_LOAD-FTC_HASH_MIN_LOAD)
/* this one _must_ be a power of 2 !! */
# define FTC_HASH_INITIAL_SIZE 8
# endif /* FTC_CACHE_USE_LINEAR_HASHING */
/*************************************************************************/
/*************************************************************************/
@ -59,11 +74,13 @@
if ( first )
{
node - > mru_prev = first - > mru_prev ;
FTC_Node last = first - > mru_prev ;
node - > mru_prev = last ;
node - > mru_next = first ;
first - > mru_prev - > mru_next = node ;
first - > mru_prev = node ;
last - > mru_next = node ;
first - > mru_prev = node ;
}
else
{
@ -114,11 +131,103 @@
if ( node ! = first )
{
ftc_node_mru_unlink ( node , manager ) ;
ftc_node_mru_link ( node , manager ) ;
FTC_Node prev = node - > mru_prev ;
FTC_Node next = node - > mru_next ;
FTC_Node last = first - > mru_prev ;
prev - > mru_next = next ;
next - > mru_prev = prev ;
node - > mru_next = first ;
node - > mru_prev = last ;
first - > mru_prev = node ;
last - > mru_next = node ;
manager - > nodes_list = node ;
}
}
# ifdef FTC_CACHE_USE_LINEAR_HASHING
/* remove a node from its cache's hash table */
static FT_Error
ftc_node_hash_unlink ( FTC_Node node ,
FTC_Cache cache )
{
FT_Error error = 0 ;
FTC_Node * pnode ;
FT_UInt index , num_buckets ;
index = ( FT_UInt ) ( node - > hash & cache - > mask ) ;
if ( index < cache - > p )
index = ( FT_UInt ) ( node - > hash & ( 2 * cache - > mask + 1 ) ) ;
pnode = cache - > buckets + index ;
for ( ; ; )
{
if ( * pnode = = NULL )
{
FT_ERROR ( ( " FreeType.cache.hash_unlink: unknown node! \n " ) ) ;
return 0 ;
}
if ( * pnode = = node )
{
* pnode = node - > link ;
node - > link = NULL ;
break ;
}
pnode = & ( * pnode ) - > link ;
}
num_buckets = ( cache - > p + cache - > mask + 1 ) ;
if ( + + cache - > slack > ( FT_Long ) num_buckets * FTC_HASH_SUB_LOAD )
{
FT_UInt p = cache - > p ;
FT_UInt mask = cache - > mask ;
FT_UInt old_index = p + mask ;
FTC_Node * pold ;
FT_ASSERT ( old_index > = FTC_HASH_INITIAL_SIZE ) ;
if ( p = = 0 )
{
FT_Memory memory = cache - > memory ;
cache - > mask > > = 1 ;
p = cache - > mask ;
if ( FT_RENEW_ARRAY ( cache - > buckets , ( mask + 1 ) * 2 , ( mask ) ) )
{
FT_ERROR ( ( " FreeType.cache.hash_unlink: couldn't shunk buckets ! \n " ) ) ;
goto Exit ;
}
}
else
p - - ;
pnode = cache - > buckets + p ;
while ( * pnode )
pnode = & ( * pnode ) - > link ;
pold = cache - > buckets + old_index ;
* pnode = * pold ;
* pold = NULL ;
cache - > slack - = FTC_HASH_MAX_LOAD ;
cache - > p = p ;
}
Exit :
return error ;
}
# else /* !FTC_CACHE_USE_LINEAR_HASHING */
/* remove a node from its cache's hash table */
static void
@ -127,7 +236,6 @@
{
FTC_Node * pnode = cache - > buckets + ( node - > hash % cache - > size ) ;
for ( ; ; )
{
if ( * pnode = = NULL )
@ -149,6 +257,81 @@
}
}
# endif /* !FTC_CACHE_USE_LINEAR_HASHING */
# ifdef FTC_CACHE_USE_LINEAR_HASHING
/* add a node to the "top" of its cache's hash table */
static FT_Error
ftc_node_hash_link ( FTC_Node node ,
FTC_Cache cache )
{
FTC_Node * pnode ;
FT_UInt index ;
FT_Error error = 0 ;
index = ( FT_UInt ) ( node - > hash & cache - > mask ) ;
if ( index < cache - > p )
index = ( FT_UInt ) ( node - > hash & ( 2 * cache - > mask + 1 ) ) ;
pnode = cache - > buckets + index ;
node - > link = * pnode ;
* pnode = node ;
if ( - - cache - > slack < 0 )
{
FT_UInt p = cache - > p ;
FT_UInt mask = cache - > mask ;
FTC_Node new_list ;
/* split a single bucket */
new_list = NULL ;
pnode = cache - > buckets + p ;
for ( ; ; )
{
node = * pnode ;
if ( node = = NULL )
break ;
if ( node - > hash & ( mask + 1 ) )
{
* pnode = node - > link ;
node - > link = new_list ;
new_list = node ;
}
else
pnode = & node - > link ;
}
cache - > buckets [ p + mask + 1 ] = new_list ;
cache - > slack + = FTC_HASH_MAX_LOAD ;
if ( p > = mask )
{
FT_Memory memory = cache - > memory ;
if ( FT_RENEW_ARRAY ( cache - > buckets , ( mask + 1 ) * 2 , ( mask + 1 ) * 4 ) )
{
FT_ERROR ( ( " FreeType.cache.hash_unlink: couldn't expand buckets ! \n " ) ) ;
goto Exit ;
}
cache - > mask = 2 * mask + 1 ;
cache - > p = 0 ;
}
else
cache - > p = p + 1 ;
}
Exit :
return error ;
}
# else /* !FTC_CACHE_USE_LINEAR_HASHING */
/* add a node to the "top" of its cache's hash table */
static void
@ -157,13 +340,15 @@
{
FTC_Node * pnode = cache - > buckets + ( node - > hash % cache - > size ) ;
node - > link = * pnode ;
* pnode = node ;
cache - > nodes + + ;
}
# endif /* !FTC_CACHE_USE_LINEAR_HASHING */
/* remove a node from the cache manager */
FT_EXPORT_DEF ( void )
@ -276,6 +461,11 @@
/*************************************************************************/
/*************************************************************************/
# ifdef FTC_CACHE_USE_LINEAR_HASHING
# else /* !FTC_CACHE_USE_LINEAR_HASHING */
# define FTC_PRIMES_MIN 7
# define FTC_PRIMES_MAX 13845163
@ -388,6 +578,7 @@
}
}
# endif /* !FTC_CACHE_USE_LINEAR_HASHING */
FT_EXPORT_DEF ( FT_Error )
ftc_cache_init ( FTC_Cache cache )
@ -397,12 +588,24 @@
FT_Error error ;
# ifdef FTC_CACHE_USE_LINEAR_HASHING
cache - > p = 0 ;
cache - > mask = FTC_HASH_INITIAL_SIZE - 1 ;
cache - > slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD ;
if ( FT_NEW_ARRAY ( cache - > buckets , FTC_HASH_INITIAL_SIZE * 2 ) )
goto Exit ;
# else /* !FTC_CACHE_USE_LINEAR_HASHING */
cache - > nodes = 0 ;
cache - > size = FTC_PRIMES_MIN ;
if ( FT_NEW_ARRAY ( cache - > buckets , cache - > size ) )
goto Exit ;
# endif /* !FTC_CACHE_USE_LINEAR_HASHING */
/* now, initialize the lru list of families for this cache */
if ( clazz - > family_size > 0 )
{
@ -442,9 +645,15 @@
FTC_Cache_Class clazz = cache - > clazz ;
FTC_Manager manager = cache - > manager ;
FT_UFast i ;
FT_UInt count ;
# ifdef FTC_CACHE_USE_LINEAR_HASHING
count = cache - > p + cache - > mask + 1 ;
# else
count = cache - > size ;
# endif
for ( i = 0 ; i < cache - > size ; i + + )
for ( i = 0 ; i < count ; i + + )
{
FTC_Node * pnode = cache - > buckets + i , next , node = * pnode ;
@ -469,8 +678,11 @@
cache - > buckets [ i ] = NULL ;
}
# ifdef FTC_CACHE_USE_LINEAR_HASHING
cache - > p = 0 ;
# else
cache - > nodes = 0 ;
# endif
/* destroy the families */
if ( cache - > families )
FT_LruList_Reset ( cache - > families ) ;
@ -489,7 +701,12 @@
ftc_cache_clear ( cache ) ;
FT_FREE ( cache - > buckets ) ;
# ifdef FTC_CACHE_USE_LINEAR_HASHING
cache - > mask = 0 ;
cache - > slack = 0 ;
# else
cache - > size = 0 ;
# endif
if ( cache - > families )
{
@ -508,7 +725,7 @@
FTC_Query query ,
FTC_Node * anode )
{
FT_Error error ;
FT_Error error = 0 ;
FT_LruNode lru ;
@ -520,12 +737,67 @@
query - > hash = 0 ;
query - > family = NULL ;
# ifdef OPT1
{
/* first of all, find the relevant family */
FT_LruList list = cache - > families ;
FT_LruNode fam , * pfam ;
FT_LruNode_CompareFunc compare = list - > clazz - > node_compare ;
pfam = & list - > nodes ;
for ( ; ; )
{
fam = * pfam ;
if ( fam = = NULL )
{
error = FT_LruList_Lookup ( list , query , & lru ) ;
if ( error )
goto Exit ;
goto Skip ;
}
if ( compare ( fam , query , list - > data ) )
break ;
pfam = & fam - > next ;
}
FT_ASSERT ( fam ! = NULL ) ;
/* move to top of list when needed */
if ( fam ! = list - > nodes )
{
* pfam = fam - > next ;
fam - > next = list - > nodes ;
list - > nodes = fam ;
}
lru = fam ;
Skip :
}
# else
error = FT_LruList_Lookup ( cache - > families , query , & lru ) ;
if ( ! error )
# endif
{
FTC_Family family = ( FTC_Family ) lru ;
FT_UFast hash = query - > hash ;
FTC_Node * bucket = cache - > buckets + ( hash % cache - > size ) ;
FTC_Node * bucket ;
# ifdef FTC_CACHE_USE_LINEAR_HASHING
FT_UInt index ;
index = hash & cache - > mask ;
if ( index < cache - > p )
index = hash & ( cache - > mask * 2 + 1 ) ;
bucket = cache - > buckets + index ;
# else
bucket = cache - > buckets + ( hash % cache - > size ) ;
# endif
if ( query - > family ! = family | |
@ -551,8 +823,14 @@
if ( node = = NULL )
break ;
# ifdef OPT1
if ( node - > hash = = hash & &
( FT_UInt ) node - > fam_index = = family - > fam_index & &
compare ( node , query , cache ) )
# else
if ( ( FT_UInt ) node - > fam_index = = family - > fam_index & &
compare ( node , query , cache ) )
# endif
{
/* move to head of bucket list */
if ( pnode ! = bucket )
@ -596,7 +874,18 @@
goto Exit ;
}
# ifdef FTC_CACHE_USE_LINEAR_HASHING
error = ftc_node_hash_link ( node , cache ) ;
if ( error )
{
clazz - > node_done ( node , cache ) ;
FT_FREE ( node ) ;
goto Exit ;
}
# else
ftc_node_hash_link ( node , cache ) ;
# endif
ftc_node_mru_link ( node , cache - > manager ) ;
cache - > manager - > cur_weight + = clazz - > node_weight ( node , cache ) ;
@ -609,9 +898,11 @@
node - > ref_count - - ;
}
# ifndef FTC_CACHE_USE_LINEAR_HASHING
/* try to resize the hash table if appropriate */
if ( FTC_CACHE_RESIZE_TEST ( cache ) )
ftc_cache_resize ( cache ) ;
# endif
* anode = node ;
}