zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ftccache.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* ftccache.c */
4 /* */
5 /* The FreeType internal cache interface (body). */
6 /* */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, */
8 /* 2011 by */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* */
11 /* This file is part of the FreeType project, and may only be used, */
12 /* modified, and distributed under the terms of the FreeType project */
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
16 /* */
17 /***************************************************************************/
18 
19 
20 #include <ft2build.h>
21 #include "ftcmanag.h"
22 #include FT_INTERNAL_OBJECTS_H
23 #include FT_INTERNAL_DEBUG_H
24 
25 #include "ftccback.h"
26 #include "ftcerror.h"
27 
28 #undef FT_COMPONENT
29 #define FT_COMPONENT trace_cache
30 
31 
32 #define FTC_HASH_MAX_LOAD 2
33 #define FTC_HASH_MIN_LOAD 1
34 #define FTC_HASH_SUB_LOAD ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD )
35 
36  /* this one _must_ be a power of 2! */
37 #define FTC_HASH_INITIAL_SIZE 8
38 
39 
40  /*************************************************************************/
41  /*************************************************************************/
42  /***** *****/
43  /***** CACHE NODE DEFINITIONS *****/
44  /***** *****/
45  /*************************************************************************/
46  /*************************************************************************/
47 
48  /* add a new node to the head of the manager's circular MRU list */
49  static void
51  FTC_Manager manager )
52  {
53  void *nl = &manager->nodes_list;
54 
55 
57  (FTC_MruNode)node );
58  manager->num_nodes++;
59  }
60 
61 
62  /* remove a node from the manager's MRU list */
63  static void
65  FTC_Manager manager )
66  {
67  void *nl = &manager->nodes_list;
68 
69 
71  (FTC_MruNode)node );
72  manager->num_nodes--;
73  }
74 
75 
76 #ifndef FTC_INLINE
77 
78  /* move a node to the head of the manager's MRU list */
79  static void
80  ftc_node_mru_up( FTC_Node node,
81  FTC_Manager manager )
82  {
84  (FTC_MruNode)node );
85  }
86 
87 
88  /* get a top bucket for specified hash from cache,
89  * body for FTC_NODE__TOP_FOR_HASH( cache, hash )
90  */
92  ftc_get_top_node_for_hash( FTC_Cache cache,
93  FT_PtrDist hash )
94  {
95  FTC_Node* pnode;
96  FT_UInt idx;
97 
98 
99  idx = (FT_UInt)( hash & cache->mask );
100  if ( idx < cache->p )
101  idx = (FT_UInt)( hash & ( 2 * cache->mask + 1 ) );
102  pnode = cache->buckets + idx;
103  return pnode;
104  }
105 
106 #endif /* !FTC_INLINE */
107 
108 
109  /* Note that this function cannot fail. If we cannot re-size the
110  * buckets array appropriately, we simply degrade the hash table's
111  * performance!
112  */
113  static void
115  {
116  for (;;)
117  {
118  FTC_Node node, *pnode;
119  FT_UFast p = cache->p;
120  FT_UFast mask = cache->mask;
121  FT_UFast count = mask + p + 1; /* number of buckets */
122 
123 
124  /* do we need to shrink the buckets array? */
125  if ( cache->slack < 0 )
126  {
127  FTC_Node new_list = NULL;
128 
129 
130  /* try to expand the buckets array _before_ splitting
131  * the bucket lists
132  */
133  if ( p >= mask )
134  {
135  FT_Memory memory = cache->memory;
136  FT_Error error;
137 
138 
139  /* if we can't expand the array, leave immediately */
140  if ( FT_RENEW_ARRAY( cache->buckets,
141  ( mask + 1 ) * 2, ( mask + 1 ) * 4 ) )
142  break;
143  }
144 
145  /* split a single bucket */
146  pnode = cache->buckets + p;
147 
148  for (;;)
149  {
150  node = *pnode;
151  if ( node == NULL )
152  break;
153 
154  if ( node->hash & ( mask + 1 ) )
155  {
156  *pnode = node->link;
157  node->link = new_list;
158  new_list = node;
159  }
160  else
161  pnode = &node->link;
162  }
163 
164  cache->buckets[p + mask + 1] = new_list;
165 
166  cache->slack += FTC_HASH_MAX_LOAD;
167 
168  if ( p >= mask )
169  {
170  cache->mask = 2 * mask + 1;
171  cache->p = 0;
172  }
173  else
174  cache->p = p + 1;
175  }
176 
177  /* do we need to expand the buckets array? */
178  else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD )
179  {
180  FT_UFast old_index = p + mask;
181  FTC_Node* pold;
182 
183 
184  if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE )
185  break;
186 
187  if ( p == 0 )
188  {
189  FT_Memory memory = cache->memory;
190  FT_Error error;
191 
192 
193  /* if we can't shrink the array, leave immediately */
194  if ( FT_RENEW_ARRAY( cache->buckets,
195  ( mask + 1 ) * 2, mask + 1 ) )
196  break;
197 
198  cache->mask >>= 1;
199  p = cache->mask;
200  }
201  else
202  p--;
203 
204  pnode = cache->buckets + p;
205  while ( *pnode )
206  pnode = &(*pnode)->link;
207 
208  pold = cache->buckets + old_index;
209  *pnode = *pold;
210  *pold = NULL;
211 
212  cache->slack -= FTC_HASH_MAX_LOAD;
213  cache->p = p;
214  }
215 
216  /* otherwise, the hash table is balanced */
217  else
218  break;
219  }
220  }
221 
222 
223  /* remove a node from its cache's hash table */
224  static void
226  FTC_Cache cache )
227  {
228  FTC_Node *pnode = FTC_NODE__TOP_FOR_HASH( cache, node0->hash );
229 
230 
231  for (;;)
232  {
233  FTC_Node node = *pnode;
234 
235 
236  if ( node == NULL )
237  {
238  FT_TRACE0(( "ftc_node_hash_unlink: unknown node\n" ));
239  return;
240  }
241 
242  if ( node == node0 )
243  break;
244 
245  pnode = &(*pnode)->link;
246  }
247 
248  *pnode = node0->link;
249  node0->link = NULL;
250 
251  cache->slack++;
252  ftc_cache_resize( cache );
253  }
254 
255 
256  /* add a node to the `top' of its cache's hash table */
257  static void
259  FTC_Cache cache )
260  {
261  FTC_Node *pnode = FTC_NODE__TOP_FOR_HASH( cache, node->hash );
262 
263 
264  node->link = *pnode;
265  *pnode = node;
266 
267  cache->slack--;
268  ftc_cache_resize( cache );
269  }
270 
271 
272  /* remove a node from the cache manager */
273 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
274  FT_BASE_DEF( void )
275 #else
276  FT_LOCAL_DEF( void )
277 #endif
279  FTC_Manager manager )
280  {
281  FTC_Cache cache;
282 
283 
284 #ifdef FT_DEBUG_ERROR
285  /* find node's cache */
286  if ( node->cache_index >= manager->num_caches )
287  {
288  FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" ));
289  return;
290  }
291 #endif
292 
293  cache = manager->caches[node->cache_index];
294 
295 #ifdef FT_DEBUG_ERROR
296  if ( cache == NULL )
297  {
298  FT_TRACE0(( "ftc_node_destroy: invalid node handle\n" ));
299  return;
300  }
301 #endif
302 
303  manager->cur_weight -= cache->clazz.node_weight( node, cache );
304 
305  /* remove node from mru list */
306  ftc_node_mru_unlink( node, manager );
307 
308  /* remove node from cache's hash table */
309  ftc_node_hash_unlink( node, cache );
310 
311  /* now finalize it */
312  cache->clazz.node_free( node, cache );
313 
314 #if 0
315  /* check, just in case of general corruption :-) */
316  if ( manager->num_nodes == 0 )
317  FT_TRACE0(( "ftc_node_destroy: invalid cache node count (%d)\n",
318  manager->num_nodes ));
319 #endif
320  }
321 
322 
323  /*************************************************************************/
324  /*************************************************************************/
325  /***** *****/
326  /***** ABSTRACT CACHE CLASS *****/
327  /***** *****/
328  /*************************************************************************/
329  /*************************************************************************/
330 
331 
334  {
335  return ftc_cache_init( cache );
336  }
337 
338 
341  {
342  FT_Memory memory = cache->memory;
343  FT_Error error;
344 
345 
346  cache->p = 0;
347  cache->mask = FTC_HASH_INITIAL_SIZE - 1;
348  cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
349 
350  (void)FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 );
351  return error;
352  }
353 
354 
355  static void
357  {
358  if ( cache && cache->buckets )
359  {
360  FTC_Manager manager = cache->manager;
361  FT_UFast i;
362  FT_UFast count;
363 
364 
365  count = cache->p + cache->mask + 1;
366 
367  for ( i = 0; i < count; i++ )
368  {
369  FTC_Node *pnode = cache->buckets + i, next, node = *pnode;
370 
371 
372  while ( node )
373  {
374  next = node->link;
375  node->link = NULL;
376 
377  /* remove node from mru list */
378  ftc_node_mru_unlink( node, manager );
379 
380  /* now finalize it */
381  manager->cur_weight -= cache->clazz.node_weight( node, cache );
382 
383  cache->clazz.node_free( node, cache );
384  node = next;
385  }
386  cache->buckets[i] = NULL;
387  }
388  ftc_cache_resize( cache );
389  }
390  }
391 
392 
393  FT_LOCAL_DEF( void )
395  {
396  if ( cache->memory )
397  {
398  FT_Memory memory = cache->memory;
399 
400 
401  FTC_Cache_Clear( cache );
402 
403  FT_FREE( cache->buckets );
404  cache->mask = 0;
405  cache->p = 0;
406  cache->slack = 0;
407 
408  cache->memory = NULL;
409  }
410  }
411 
412 
413  FT_LOCAL_DEF( void )
415  {
416  ftc_cache_done( cache );
417  }
418 
419 
420  static void
422  FT_PtrDist hash,
423  FTC_Node node )
424  {
425  node->hash = hash;
426  node->cache_index = (FT_UInt16)cache->index;
427  node->ref_count = 0;
428 
429  ftc_node_hash_link( node, cache );
430  ftc_node_mru_link( node, cache->manager );
431 
432  {
433  FTC_Manager manager = cache->manager;
434 
435 
436  manager->cur_weight += cache->clazz.node_weight( node, cache );
437 
438  if ( manager->cur_weight >= manager->max_weight )
439  {
440  node->ref_count++;
441  FTC_Manager_Compress( manager );
442  node->ref_count--;
443  }
444  }
445  }
446 
447 
450  FT_PtrDist hash,
452  FTC_Node *anode )
453  {
454  FT_Error error;
455  FTC_Node node;
456 
457 
458  /*
459  * We use the FTC_CACHE_TRYLOOP macros to support out-of-memory
460  * errors (OOM) correctly, i.e., by flushing the cache progressively
461  * in order to make more room.
462  */
463 
464  FTC_CACHE_TRYLOOP( cache )
465  {
466  error = cache->clazz.node_new( &node, query, cache );
467  }
469 
470  if ( error )
471  node = NULL;
472  else
473  {
474  /* don't assume that the cache has the same number of buckets, since
475  * our allocation request might have triggered global cache flushing
476  */
477  ftc_cache_add( cache, hash, node );
478  }
479 
480  *anode = node;
481  return error;
482  }
483 
484 
485 #ifndef FTC_INLINE
486 
488  FTC_Cache_Lookup( FTC_Cache cache,
489  FT_PtrDist hash,
491  FTC_Node *anode )
492  {
493  FTC_Node* bucket;
494  FTC_Node* pnode;
495  FTC_Node node;
496  FT_Error error = FTC_Err_Ok;
497  FT_Bool list_changed = FALSE;
498 
499  FTC_Node_CompareFunc compare = cache->clazz.node_compare;
500 
501 
502  if ( cache == NULL || anode == NULL )
503  return FTC_Err_Invalid_Argument;
504 
505  /* Go to the `top' node of the list sharing same masked hash */
506  bucket = pnode = FTC_NODE__TOP_FOR_HASH( cache, hash );
507 
508  /* Lookup a node with exactly same hash and queried properties. */
509  /* NOTE: _nodcomp() may change the linked list to reduce memory. */
510  for (;;)
511  {
512  node = *pnode;
513  if ( node == NULL )
514  goto NewNode;
515 
516  if ( node->hash == hash &&
517  compare( node, query, cache, &list_changed ) )
518  break;
519 
520  pnode = &node->link;
521  }
522 
523  if ( list_changed )
524  {
525  /* Update bucket by modified linked list */
526  bucket = pnode = FTC_NODE__TOP_FOR_HASH( cache, hash );
527 
528  /* Update pnode by modified linked list */
529  while ( *pnode != node )
530  {
531  if ( *pnode == NULL )
532  {
533  FT_ERROR(( "FTC_Cache_Lookup: oops!!! node missing\n" ));
534  goto NewNode;
535  }
536  else
537  pnode = &((*pnode)->link);
538  }
539  }
540 
541  /* Reorder the list to move the found node to the `top' */
542  if ( node != *bucket )
543  {
544  *pnode = node->link;
545  node->link = *bucket;
546  *bucket = node;
547  }
548 
549  /* move to head of MRU list */
550  {
551  FTC_Manager manager = cache->manager;
552 
553 
554  if ( node != manager->nodes_list )
555  ftc_node_mru_up( node, manager );
556  }
557  *anode = node;
558 
559  return error;
560 
561  NewNode:
562  return FTC_Cache_NewNode( cache, hash, query, anode );
563  }
564 
565 #endif /* !FTC_INLINE */
566 
567 
568  FT_LOCAL_DEF( void )
570  FTC_FaceID face_id )
571  {
572  FT_UFast i, count;
573  FTC_Manager manager = cache->manager;
574  FTC_Node frees = NULL;
575 
576 
577  count = cache->p + cache->mask + 1;
578  for ( i = 0; i < count; i++ )
579  {
580  FTC_Node* bucket = cache->buckets + i;
581  FTC_Node* pnode = bucket;
582 
583 
584  for ( ;; )
585  {
586  FTC_Node node = *pnode;
587  FT_Bool list_changed = FALSE;
588 
589 
590  if ( node == NULL )
591  break;
592 
593  if ( cache->clazz.node_remove_faceid( node, face_id,
594  cache, &list_changed ) )
595  {
596  *pnode = node->link;
597  node->link = frees;
598  frees = node;
599  }
600  else
601  pnode = &node->link;
602  }
603  }
604 
605  /* remove all nodes in the free list */
606  while ( frees )
607  {
608  FTC_Node node;
609 
610 
611  node = frees;
612  frees = node->link;
613 
614  manager->cur_weight -= cache->clazz.node_weight( node, cache );
615  ftc_node_mru_unlink( node, manager );
616 
617  cache->clazz.node_free( node, cache );
618 
619  cache->slack++;
620  }
621 
622  ftc_cache_resize( cache );
623  }
624 
625 
626 /* END */
static void ftc_node_hash_link(FTC_Node node, FTC_Cache cache)
Definition: ftccache.c:258
int FT_Error
Definition: fttypes.h:296
#define FTC_CACHE_TRYLOOP_END(list_changed)
Definition: ftccache.h:330
ft_ptrdiff_t FT_PtrDist
Definition: fttypes.h:333
signed long FT_Long
Definition: fttypes.h:238
FT_ULong cur_weight
Definition: ftcmanag.h:98
FTC_CacheClassRec clazz
Definition: ftccache.h:157
FTC_Manager manager
Definition: ftccache.h:159
FT_UFast mask
Definition: ftccache.h:153
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
unsigned short FT_UInt16
Definition: ftconfig.h:176
FTC_Node link
Definition: ftccache.h:62
FTC_Manager_Compress(FTC_Manager manager)
Definition: ftcmanag.c:532
#define NULL
Definition: ftobjs.h:61
typedefFT_BEGIN_HEADER struct FTC_MruNodeRec_ * FTC_MruNode
Definition: ftcmru.h:61
FT_UInt num_nodes
Definition: ftcmanag.h:99
FT_UFast p
Definition: ftccache.h:152
FT_Short ref_count
Definition: ftccache.h:65
FTC_MruNode_Remove(FTC_MruNode *plist, FTC_MruNode node)
Definition: ftcmru.c:122
FT_UShort cache_index
Definition: ftccache.h:64
#define FTC_CACHE_TRYLOOP(cache)
Definition: ftccache.h:319
FT_BEGIN_HEADER typedef FT_Pointer FTC_FaceID
Definition: ftcache.h:171
ftc_cache_init(FTC_Cache cache)
Definition: ftccache.c:340
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:104
FT_Long slack
Definition: ftccache.h:154
#define FT_ERROR(varformat)
Definition: ftdebug.h:181
FTC_Node_FreeFunc node_free
Definition: ftccache.h:140
FTC_Node * buckets
Definition: ftccache.h:155
FTC_Cache_Done(FTC_Cache cache)
Definition: ftccache.c:414
#define FTC_HASH_MAX_LOAD
Definition: ftccache.c:32
GLenum query
Definition: glew.h:5140
#define FT_FREE(ptr)
Definition: ftmemory.h:286
FTC_Cache_NewNode(FTC_Cache cache, FT_PtrDist hash, FT_Pointer query, FTC_Node *anode)
Definition: ftccache.c:449
#define FTC_HASH_SUB_LOAD
Definition: ftccache.c:34
#define FTC_HASH_INITIAL_SIZE
Definition: ftccache.c:37
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:467
FT_UInt idx
Definition: cffcmap.c:125
static void ftc_cache_resize(FTC_Cache cache)
Definition: ftccache.c:114
FT_Memory memory
Definition: ftccache.h:160
FT_Error error
Definition: cffdrivr.c:407
FTC_Node_WeightFunc node_weight
Definition: ftccache.h:137
#define FT_TRACE0(varformat)
Definition: ftdebug.h:157
void * FT_Pointer
Definition: fttypes.h:307
GLint GLsizei count
Definition: gl2ext.h:1011
static void ftc_cache_add(FTC_Cache cache, FT_PtrDist hash, FTC_Node node)
Definition: ftccache.c:421
FTC_MruNode_Up(FTC_MruNode *plist, FTC_MruNode node)
Definition: ftcmru.c:73
GLfloat GLfloat p
Definition: glew.h:14938
static void ftc_node_hash_unlink(FTC_Node node0, FTC_Cache cache)
Definition: ftccache.c:225
#define FT_RENEW_ARRAY(ptr, curcnt, newcnt)
Definition: ftmemory.h:293
ftc_node_destroy(FTC_Node node, FTC_Manager manager)
Definition: ftccache.c:278
#define FALSE
Definition: ftobjs.h:57
FTC_Cache caches[FTC_MAX_CACHES]
Definition: ftcmanag.h:101
static void ftc_node_mru_link(FTC_Node node, FTC_Manager manager)
Definition: ftccache.c:50
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:66
FT_UInt num_caches
Definition: ftcmanag.h:102
#define FT_NEW_ARRAY(ptr, count)
Definition: ftmemory.h:290
FTC_Cache_RemoveFaceID(FTC_Cache cache, FTC_FaceID face_id)
Definition: ftccache.c:569
unsigned int FT_UInt
Definition: fttypes.h:227
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
Definition: gl2ext.h:961
FT_PtrDist hash
Definition: ftccache.h:63
#define FT_BASE_DEF(x)
Definition: ftconfig.h:489
#define FTC_NODE__TOP_FOR_HASH(cache, hash)
Definition: ftccache.h:77
static void FTC_Cache_Clear(FTC_Cache cache)
Definition: ftccache.c:356
int i
Definition: pngrutil.c:1377
FTC_Cache_Init(FTC_Cache cache)
Definition: ftccache.c:333
FT_Bool(* FTC_Node_CompareFunc)(FTC_Node node, FT_Pointer key, FTC_Cache cache, FT_Bool *list_changed)
Definition: ftccache.h:117
FT_ULong max_weight
Definition: ftcmanag.h:97
FT_UInt index
Definition: ftccache.h:161
FTC_Node nodes_list
Definition: ftcmanag.h:96
ftc_cache_done(FTC_Cache cache)
Definition: ftccache.c:394
static void ftc_node_mru_unlink(FTC_Node node, FTC_Manager manager)
Definition: ftccache.c:64
FTC_MruNode_Prepend(FTC_MruNode *plist, FTC_MruNode node)
Definition: ftcmru.c:29