1*37da2899SCharles.Forsyth /***************************************************************************/ 2*37da2899SCharles.Forsyth /* */ 3*37da2899SCharles.Forsyth /* ftlru.c */ 4*37da2899SCharles.Forsyth /* */ 5*37da2899SCharles.Forsyth /* Simple LRU list-cache (body). */ 6*37da2899SCharles.Forsyth /* */ 7*37da2899SCharles.Forsyth /* Copyright 2000-2001, 2002 by */ 8*37da2899SCharles.Forsyth /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9*37da2899SCharles.Forsyth /* */ 10*37da2899SCharles.Forsyth /* This file is part of the FreeType project, and may only be used, */ 11*37da2899SCharles.Forsyth /* modified, and distributed under the terms of the FreeType project */ 12*37da2899SCharles.Forsyth /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13*37da2899SCharles.Forsyth /* this file you indicate that you have read the license and */ 14*37da2899SCharles.Forsyth /* understand and accept it fully. */ 15*37da2899SCharles.Forsyth /* */ 16*37da2899SCharles.Forsyth /***************************************************************************/ 17*37da2899SCharles.Forsyth 18*37da2899SCharles.Forsyth 19*37da2899SCharles.Forsyth #include <ft2build.h> 20*37da2899SCharles.Forsyth #include FT_CACHE_H 21*37da2899SCharles.Forsyth #include FT_CACHE_INTERNAL_LRU_H 22*37da2899SCharles.Forsyth #include FT_LIST_H 23*37da2899SCharles.Forsyth #include FT_INTERNAL_OBJECTS_H 24*37da2899SCharles.Forsyth 25*37da2899SCharles.Forsyth #include "ftcerror.h" 26*37da2899SCharles.Forsyth 27*37da2899SCharles.Forsyth 28*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_LruList_New(FT_LruList_Class clazz,FT_UInt max_nodes,FT_Pointer user_data,FT_Memory memory,FT_LruList * alist)29*37da2899SCharles.Forsyth FT_LruList_New( FT_LruList_Class clazz, 30*37da2899SCharles.Forsyth FT_UInt max_nodes, 31*37da2899SCharles.Forsyth FT_Pointer user_data, 32*37da2899SCharles.Forsyth FT_Memory memory, 33*37da2899SCharles.Forsyth FT_LruList *alist ) 34*37da2899SCharles.Forsyth { 35*37da2899SCharles.Forsyth FT_Error error; 36*37da2899SCharles.Forsyth FT_LruList list; 37*37da2899SCharles.Forsyth 38*37da2899SCharles.Forsyth 39*37da2899SCharles.Forsyth if ( !alist || !clazz ) 40*37da2899SCharles.Forsyth return FTC_Err_Invalid_Argument; 41*37da2899SCharles.Forsyth 42*37da2899SCharles.Forsyth *alist = NULL; 43*37da2899SCharles.Forsyth if ( !FT_ALLOC( list, clazz->list_size ) ) 44*37da2899SCharles.Forsyth { 45*37da2899SCharles.Forsyth /* initialize common fields */ 46*37da2899SCharles.Forsyth list->clazz = clazz; 47*37da2899SCharles.Forsyth list->memory = memory; 48*37da2899SCharles.Forsyth list->max_nodes = max_nodes; 49*37da2899SCharles.Forsyth list->data = user_data; 50*37da2899SCharles.Forsyth 51*37da2899SCharles.Forsyth if ( clazz->list_init ) 52*37da2899SCharles.Forsyth { 53*37da2899SCharles.Forsyth error = clazz->list_init( list ); 54*37da2899SCharles.Forsyth if ( error ) 55*37da2899SCharles.Forsyth { 56*37da2899SCharles.Forsyth if ( clazz->list_done ) 57*37da2899SCharles.Forsyth clazz->list_done( list ); 58*37da2899SCharles.Forsyth 59*37da2899SCharles.Forsyth FT_FREE( list ); 60*37da2899SCharles.Forsyth } 61*37da2899SCharles.Forsyth } 62*37da2899SCharles.Forsyth 63*37da2899SCharles.Forsyth *alist = list; 64*37da2899SCharles.Forsyth } 65*37da2899SCharles.Forsyth 66*37da2899SCharles.Forsyth return error; 67*37da2899SCharles.Forsyth } 68*37da2899SCharles.Forsyth 69*37da2899SCharles.Forsyth 70*37da2899SCharles.Forsyth FT_EXPORT_DEF( void ) FT_LruList_Destroy(FT_LruList list)71*37da2899SCharles.Forsyth FT_LruList_Destroy( FT_LruList list ) 72*37da2899SCharles.Forsyth { 73*37da2899SCharles.Forsyth FT_Memory memory; 74*37da2899SCharles.Forsyth FT_LruList_Class clazz; 75*37da2899SCharles.Forsyth 76*37da2899SCharles.Forsyth 77*37da2899SCharles.Forsyth if ( !list ) 78*37da2899SCharles.Forsyth return; 79*37da2899SCharles.Forsyth 80*37da2899SCharles.Forsyth memory = list->memory; 81*37da2899SCharles.Forsyth clazz = list->clazz; 82*37da2899SCharles.Forsyth 83*37da2899SCharles.Forsyth FT_LruList_Reset( list ); 84*37da2899SCharles.Forsyth 85*37da2899SCharles.Forsyth if ( clazz->list_done ) 86*37da2899SCharles.Forsyth clazz->list_done( list ); 87*37da2899SCharles.Forsyth 88*37da2899SCharles.Forsyth FT_FREE( list ); 89*37da2899SCharles.Forsyth } 90*37da2899SCharles.Forsyth 91*37da2899SCharles.Forsyth 92*37da2899SCharles.Forsyth FT_EXPORT_DEF( void ) FT_LruList_Reset(FT_LruList list)93*37da2899SCharles.Forsyth FT_LruList_Reset( FT_LruList list ) 94*37da2899SCharles.Forsyth { 95*37da2899SCharles.Forsyth FT_LruNode node; 96*37da2899SCharles.Forsyth FT_LruList_Class clazz; 97*37da2899SCharles.Forsyth FT_Memory memory; 98*37da2899SCharles.Forsyth 99*37da2899SCharles.Forsyth 100*37da2899SCharles.Forsyth if ( !list ) 101*37da2899SCharles.Forsyth return; 102*37da2899SCharles.Forsyth 103*37da2899SCharles.Forsyth node = list->nodes; 104*37da2899SCharles.Forsyth clazz = list->clazz; 105*37da2899SCharles.Forsyth memory = list->memory; 106*37da2899SCharles.Forsyth 107*37da2899SCharles.Forsyth while ( node ) 108*37da2899SCharles.Forsyth { 109*37da2899SCharles.Forsyth FT_LruNode next = node->next; 110*37da2899SCharles.Forsyth 111*37da2899SCharles.Forsyth 112*37da2899SCharles.Forsyth if ( clazz->node_done ) 113*37da2899SCharles.Forsyth clazz->node_done( node, list->data ); 114*37da2899SCharles.Forsyth 115*37da2899SCharles.Forsyth FT_FREE( node ); 116*37da2899SCharles.Forsyth node = next; 117*37da2899SCharles.Forsyth } 118*37da2899SCharles.Forsyth 119*37da2899SCharles.Forsyth list->nodes = NULL; 120*37da2899SCharles.Forsyth list->num_nodes = 0; 121*37da2899SCharles.Forsyth } 122*37da2899SCharles.Forsyth 123*37da2899SCharles.Forsyth 124*37da2899SCharles.Forsyth FT_EXPORT_DEF( FT_Error ) FT_LruList_Lookup(FT_LruList list,FT_LruKey key,FT_LruNode * anode)125*37da2899SCharles.Forsyth FT_LruList_Lookup( FT_LruList list, 126*37da2899SCharles.Forsyth FT_LruKey key, 127*37da2899SCharles.Forsyth FT_LruNode *anode ) 128*37da2899SCharles.Forsyth { 129*37da2899SCharles.Forsyth FT_Error error = 0; 130*37da2899SCharles.Forsyth FT_LruNode node, *pnode; 131*37da2899SCharles.Forsyth FT_LruList_Class clazz; 132*37da2899SCharles.Forsyth FT_LruNode* plast; 133*37da2899SCharles.Forsyth FT_LruNode result = NULL; 134*37da2899SCharles.Forsyth FT_Memory memory; 135*37da2899SCharles.Forsyth 136*37da2899SCharles.Forsyth 137*37da2899SCharles.Forsyth if ( !list || !key || !anode ) 138*37da2899SCharles.Forsyth return FTC_Err_Invalid_Argument; 139*37da2899SCharles.Forsyth 140*37da2899SCharles.Forsyth pnode = &list->nodes; 141*37da2899SCharles.Forsyth plast = pnode; 142*37da2899SCharles.Forsyth node = NULL; 143*37da2899SCharles.Forsyth clazz = list->clazz; 144*37da2899SCharles.Forsyth memory = list->memory; 145*37da2899SCharles.Forsyth 146*37da2899SCharles.Forsyth if ( clazz->node_compare ) 147*37da2899SCharles.Forsyth { 148*37da2899SCharles.Forsyth for (;;) 149*37da2899SCharles.Forsyth { 150*37da2899SCharles.Forsyth node = *pnode; 151*37da2899SCharles.Forsyth if ( node == NULL ) 152*37da2899SCharles.Forsyth break; 153*37da2899SCharles.Forsyth 154*37da2899SCharles.Forsyth if ( clazz->node_compare( node, key, list->data ) ) 155*37da2899SCharles.Forsyth break; 156*37da2899SCharles.Forsyth 157*37da2899SCharles.Forsyth plast = pnode; 158*37da2899SCharles.Forsyth pnode = &(*pnode)->next; 159*37da2899SCharles.Forsyth } 160*37da2899SCharles.Forsyth } 161*37da2899SCharles.Forsyth else 162*37da2899SCharles.Forsyth { 163*37da2899SCharles.Forsyth for (;;) 164*37da2899SCharles.Forsyth { 165*37da2899SCharles.Forsyth node = *pnode; 166*37da2899SCharles.Forsyth if ( node == NULL ) 167*37da2899SCharles.Forsyth break; 168*37da2899SCharles.Forsyth 169*37da2899SCharles.Forsyth if ( node->key == key ) 170*37da2899SCharles.Forsyth break; 171*37da2899SCharles.Forsyth 172*37da2899SCharles.Forsyth plast = pnode; 173*37da2899SCharles.Forsyth pnode = &(*pnode)->next; 174*37da2899SCharles.Forsyth } 175*37da2899SCharles.Forsyth } 176*37da2899SCharles.Forsyth 177*37da2899SCharles.Forsyth if ( node ) 178*37da2899SCharles.Forsyth { 179*37da2899SCharles.Forsyth /* move element to top of list */ 180*37da2899SCharles.Forsyth if ( list->nodes != node ) 181*37da2899SCharles.Forsyth { 182*37da2899SCharles.Forsyth *pnode = node->next; 183*37da2899SCharles.Forsyth node->next = list->nodes; 184*37da2899SCharles.Forsyth list->nodes = node; 185*37da2899SCharles.Forsyth } 186*37da2899SCharles.Forsyth result = node; 187*37da2899SCharles.Forsyth goto Exit; 188*37da2899SCharles.Forsyth } 189*37da2899SCharles.Forsyth 190*37da2899SCharles.Forsyth /* we haven't found the relevant element. We will now try */ 191*37da2899SCharles.Forsyth /* to create a new one. */ 192*37da2899SCharles.Forsyth /* */ 193*37da2899SCharles.Forsyth 194*37da2899SCharles.Forsyth /* first, check if our list if full, when appropriate */ 195*37da2899SCharles.Forsyth if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes ) 196*37da2899SCharles.Forsyth { 197*37da2899SCharles.Forsyth /* this list list is full; we will now flush */ 198*37da2899SCharles.Forsyth /* the oldest node, if there's one! */ 199*37da2899SCharles.Forsyth FT_LruNode last = *plast; 200*37da2899SCharles.Forsyth 201*37da2899SCharles.Forsyth 202*37da2899SCharles.Forsyth if ( last ) 203*37da2899SCharles.Forsyth { 204*37da2899SCharles.Forsyth if ( clazz->node_flush ) 205*37da2899SCharles.Forsyth { 206*37da2899SCharles.Forsyth error = clazz->node_flush( last, key, list->data ); 207*37da2899SCharles.Forsyth } 208*37da2899SCharles.Forsyth else 209*37da2899SCharles.Forsyth { 210*37da2899SCharles.Forsyth if ( clazz->node_done ) 211*37da2899SCharles.Forsyth clazz->node_done( last, list->data ); 212*37da2899SCharles.Forsyth 213*37da2899SCharles.Forsyth last->key = key; 214*37da2899SCharles.Forsyth error = clazz->node_init( last, key, list->data ); 215*37da2899SCharles.Forsyth } 216*37da2899SCharles.Forsyth 217*37da2899SCharles.Forsyth if ( !error ) 218*37da2899SCharles.Forsyth { 219*37da2899SCharles.Forsyth /* move it to the top of the list */ 220*37da2899SCharles.Forsyth *plast = NULL; 221*37da2899SCharles.Forsyth last->next = list->nodes; 222*37da2899SCharles.Forsyth list->nodes = last; 223*37da2899SCharles.Forsyth 224*37da2899SCharles.Forsyth result = last; 225*37da2899SCharles.Forsyth goto Exit; 226*37da2899SCharles.Forsyth } 227*37da2899SCharles.Forsyth 228*37da2899SCharles.Forsyth /* in case of error during the flush or done/init cycle, */ 229*37da2899SCharles.Forsyth /* we need to discard the node */ 230*37da2899SCharles.Forsyth if ( clazz->node_done ) 231*37da2899SCharles.Forsyth clazz->node_done( last, list->data ); 232*37da2899SCharles.Forsyth 233*37da2899SCharles.Forsyth *plast = NULL; 234*37da2899SCharles.Forsyth list->num_nodes--; 235*37da2899SCharles.Forsyth 236*37da2899SCharles.Forsyth FT_FREE( last ); 237*37da2899SCharles.Forsyth goto Exit; 238*37da2899SCharles.Forsyth } 239*37da2899SCharles.Forsyth } 240*37da2899SCharles.Forsyth 241*37da2899SCharles.Forsyth /* otherwise, simply allocate a new node */ 242*37da2899SCharles.Forsyth if ( FT_ALLOC( node, clazz->node_size ) ) 243*37da2899SCharles.Forsyth goto Exit; 244*37da2899SCharles.Forsyth 245*37da2899SCharles.Forsyth node->key = key; 246*37da2899SCharles.Forsyth error = clazz->node_init( node, key, list->data ); 247*37da2899SCharles.Forsyth if ( error ) 248*37da2899SCharles.Forsyth { 249*37da2899SCharles.Forsyth FT_FREE( node ); 250*37da2899SCharles.Forsyth goto Exit; 251*37da2899SCharles.Forsyth } 252*37da2899SCharles.Forsyth 253*37da2899SCharles.Forsyth result = node; 254*37da2899SCharles.Forsyth node->next = list->nodes; 255*37da2899SCharles.Forsyth list->nodes = node; 256*37da2899SCharles.Forsyth list->num_nodes++; 257*37da2899SCharles.Forsyth 258*37da2899SCharles.Forsyth Exit: 259*37da2899SCharles.Forsyth *anode = result; 260*37da2899SCharles.Forsyth return error; 261*37da2899SCharles.Forsyth } 262*37da2899SCharles.Forsyth 263*37da2899SCharles.Forsyth 264*37da2899SCharles.Forsyth FT_EXPORT_DEF( void ) FT_LruList_Remove(FT_LruList list,FT_LruNode node)265*37da2899SCharles.Forsyth FT_LruList_Remove( FT_LruList list, 266*37da2899SCharles.Forsyth FT_LruNode node ) 267*37da2899SCharles.Forsyth { 268*37da2899SCharles.Forsyth FT_LruNode *pnode; 269*37da2899SCharles.Forsyth 270*37da2899SCharles.Forsyth 271*37da2899SCharles.Forsyth if ( !list || !node ) 272*37da2899SCharles.Forsyth return; 273*37da2899SCharles.Forsyth 274*37da2899SCharles.Forsyth pnode = &list->nodes; 275*37da2899SCharles.Forsyth for (;;) 276*37da2899SCharles.Forsyth { 277*37da2899SCharles.Forsyth if ( *pnode == node ) 278*37da2899SCharles.Forsyth { 279*37da2899SCharles.Forsyth FT_Memory memory = list->memory; 280*37da2899SCharles.Forsyth FT_LruList_Class clazz = list->clazz; 281*37da2899SCharles.Forsyth 282*37da2899SCharles.Forsyth 283*37da2899SCharles.Forsyth *pnode = node->next; 284*37da2899SCharles.Forsyth node->next = NULL; 285*37da2899SCharles.Forsyth 286*37da2899SCharles.Forsyth if ( clazz->node_done ) 287*37da2899SCharles.Forsyth clazz->node_done( node, list->data ); 288*37da2899SCharles.Forsyth 289*37da2899SCharles.Forsyth FT_FREE( node ); 290*37da2899SCharles.Forsyth list->num_nodes--; 291*37da2899SCharles.Forsyth break; 292*37da2899SCharles.Forsyth } 293*37da2899SCharles.Forsyth 294*37da2899SCharles.Forsyth pnode = &(*pnode)->next; 295*37da2899SCharles.Forsyth } 296*37da2899SCharles.Forsyth } 297*37da2899SCharles.Forsyth 298*37da2899SCharles.Forsyth 299*37da2899SCharles.Forsyth FT_EXPORT_DEF( void ) FT_LruList_Remove_Selection(FT_LruList list,FT_LruNode_SelectFunc select_func,FT_Pointer select_data)300*37da2899SCharles.Forsyth FT_LruList_Remove_Selection( FT_LruList list, 301*37da2899SCharles.Forsyth FT_LruNode_SelectFunc select_func, 302*37da2899SCharles.Forsyth FT_Pointer select_data ) 303*37da2899SCharles.Forsyth { 304*37da2899SCharles.Forsyth FT_LruNode *pnode, node; 305*37da2899SCharles.Forsyth FT_LruList_Class clazz; 306*37da2899SCharles.Forsyth FT_Memory memory; 307*37da2899SCharles.Forsyth 308*37da2899SCharles.Forsyth 309*37da2899SCharles.Forsyth if ( !list || !select_func ) 310*37da2899SCharles.Forsyth return; 311*37da2899SCharles.Forsyth 312*37da2899SCharles.Forsyth memory = list->memory; 313*37da2899SCharles.Forsyth clazz = list->clazz; 314*37da2899SCharles.Forsyth pnode = &list->nodes; 315*37da2899SCharles.Forsyth 316*37da2899SCharles.Forsyth for (;;) 317*37da2899SCharles.Forsyth { 318*37da2899SCharles.Forsyth node = *pnode; 319*37da2899SCharles.Forsyth if ( node == NULL ) 320*37da2899SCharles.Forsyth break; 321*37da2899SCharles.Forsyth 322*37da2899SCharles.Forsyth if ( select_func( node, select_data, list->data ) ) 323*37da2899SCharles.Forsyth { 324*37da2899SCharles.Forsyth *pnode = node->next; 325*37da2899SCharles.Forsyth node->next = NULL; 326*37da2899SCharles.Forsyth 327*37da2899SCharles.Forsyth if ( clazz->node_done ) 328*37da2899SCharles.Forsyth clazz->node_done( node, list ); 329*37da2899SCharles.Forsyth 330*37da2899SCharles.Forsyth FT_FREE( node ); 331*37da2899SCharles.Forsyth } 332*37da2899SCharles.Forsyth else 333*37da2899SCharles.Forsyth pnode = &(*pnode)->next; 334*37da2899SCharles.Forsyth } 335*37da2899SCharles.Forsyth } 336*37da2899SCharles.Forsyth 337*37da2899SCharles.Forsyth 338*37da2899SCharles.Forsyth /* END */ 339