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