From ba600671f107e84c47966251b1ee193113fc3ae5 Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 23 Aug 2000 11:22:30 +0000 Subject: [PATCH] The FreeType Caching Subsystem - first lines of code beware, this code is not tested, and probably doesn't compile correctly.. more information will follow.. --- src/cache/ftcimage.c | 147 +++++++++++++++++++++++ src/cache/ftcimage.h | 104 ++++++++++++++++ src/cache/ftcmanag.c | 280 +++++++++++++++++++++++++++++++++++++++++++ src/cache/ftcmanag.h | 65 ++++++++++ src/cache/ftlru.c | 263 ++++++++++++++++++++++++++++++++++++++++ src/cache/ftlru.h | 83 +++++++++++++ 6 files changed, 942 insertions(+) create mode 100644 src/cache/ftcimage.c create mode 100644 src/cache/ftcimage.h create mode 100644 src/cache/ftcmanag.c create mode 100644 src/cache/ftcmanag.h create mode 100644 src/cache/ftlru.c create mode 100644 src/cache/ftlru.h diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c new file mode 100644 index 000000000..3c735e41b --- /dev/null +++ b/src/cache/ftcimage.c @@ -0,0 +1,147 @@ +#include + + static + void ftc_done_glyph_image( FTC_Image_Queue queue, + FTC_ImageNode node ) + { + FT_UNUSED(queue); + FT_Done_Glyph( FTC_IMAGENODE_GET_GLYPH(node) ); + } + + static + FT_ULong ftc_size_bitmap_image( FTC_Image_Queue queue, + FTC_ImageNode node ) + { + FT_Long pitch; + FT_BitmapGlyph glyph; + + FT_UNUSED(queue); + glyph = (FT_BitmapGlyph)FTC_IMAGENODE_GET_GLYPH(node); + pitch = glyph->bitmap.pitch; + if (pitch < 0) + pitch = -pitch; + + return (FT_ULong)(pitch * glyph->bitmap->rows + sizeof(*glyph)); + } + + static + FT_ULong ftc_size_outline_image( FTC_Image_Queue queue, + FTC_ImageNode node ) + { + FT_Long pitch; + FT_OutlineGlyph glyph; + FT_Outline* outline; + + FT_UNUSED(queue); + glyph = (FT_OutlineGlyph)FTC_IMAGENODE_GET_GLYPH(node); + outline = &glyph->outline; + + return (FT_ULong)( + outline->n_points * (sizeof(FT_Vector)+sizeof(FT_Byte)) + + outline->n_contours * sizeof(FT_Short) + + sizeof(*glyph) ); + } + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** MONOCHROME BITMAP CALLBACKS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + static + FT_Error ftc_init_mono_image( FTC_Image_Queue queue, + FTC_ImageNode node ) + { + FT_Face face; + FT_Size size; + FT_Error error; + + + error = FTC_Manager_Lookup_Size( queue->manager, + &queue->size_rec, + &face, &size ); + if (!error) + { + FT_UInt glyph_index = FTC_IMAGENODE_GINDEX(node); + + + error = FT_Load_Glyph( face, glyph_index, + FT_LOAD_RENDER | FT_LOAD_MONOCHROME ); + if (!error) + { + if ( face->glyph->format != ft_image_format_bitmap || + face->glyph->bitmap.pixel_mode != ft_pixel_mode_mono ) + { + /* there is no monochrome glyph for this font !! */ + error = FT_Err_Invalid_Glyph_Index; + } + else + { + /* ok, copy it */ + FT_Glyph glyph; + + + error = FT_Get_Glyph( face->glyph, &glyph ); + if (!error) + FTC_IMAGENODE_SET_GLYPH(node,glyph); + } + } + } + return error; + } + + + static + FT_Error ftc_init_gray_image( FTC_Image_Queue queue, + FTC_ImageNode node ) + { + FT_Face face; + FT_Size size; + FT_Error error; + + + error = FTC_Manager_Lookup_Size( queue->manager, + &queue->size_rec, + &face, &size ); + if (!error) + { + FT_UInt glyph_index = FTC_IMAGENODE_GINDEX(node); + + + error = FT_Load_Glyph( face, glyph_index, + FT_LOAD_RENDER ); + if (!error) + { + if ( face->glyph->format != ft_image_format_bitmap || + face->glyph->bitmap.pixel_mode != ft_pixel_mode_grays ) + { + /* there is no monochrome glyph for this font !! */ + error = FT_Err_Invalid_Glyph_Index; + } + else + { + /* ok, copy it */ + FT_Glyph glyph; + + + error = FT_Get_Glyph( face->glyph, &glyph ); + if (!error) + FTC_IMAGENODE_SET_GLYPH(node,glyph); + } + } + } + return error; + } + + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** MONOCHROME BITMAP CALLBACKS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + diff --git a/src/cache/ftcimage.h b/src/cache/ftcimage.h new file mode 100644 index 000000000..ae00ce75f --- /dev/null +++ b/src/cache/ftcimage.h @@ -0,0 +1,104 @@ +#ifndef FTCIMAGE_H +#define FTCIMAGE_H + +#include +#include + + typedef struct FTC_Image_QueueRec_* FTC_Image_Queue; + typedef struct FTC_Image_CacheRec_* FTC_Image_Cache; + typedef struct FTC_ImageNodeRec_* FTC_ImageNode; + + /* types of glyph images */ + typedef enum FTC_Image_Type_ + { + ftc_image_mono = 0, /* monochrome bitmap */ + ftc_image_grays, /* anti-aliased bitmap */ + ftc_image_outline, /* scaled outline */ + ftc_image_master_outline, /* original outline */ + + } FTC_Image_Type; + + + /* a descriptor used to describe all glyphs in a given queue */ + typedef struct FTC_Image_Desc_ + { + FTC_FaceID face_id; + FT_UInt pix_width; + FT_UInt pix_height; + FT_UInt image_type; + + } FTC_Image_Desc; + +/* macros used to pack a glyph index and a queue index in a single ptr */ +#define FTC_PTR_TO_GINDEX(p) ((FT_UInt)((FT_ULong)(p) >> 16)) +#define FTC_PTR_TO_QINDEX(p) ((FT_UInt)((FT_ULong)(p) & 0xFFFF)) +#define FTC_INDICES_TO_PTR(g,q) ((FT_Pointer)(((FT_ULong)(g) << 16) | \ + ((FT_ULong)(q) & 0xFFFF))) + + typedef struct FTC_ImageNodeRec_ + { + FT_ListNodeRec root1; /* root1.data contains a FT_Glyph handle */ + FT_ListNodeRec root2; /* root2.data contains a glyph index + queue index */ + + } FTC_ImageNodeRec; + +/* macros to read/set the glyph & queue index in a FTC_ImageNode */ +#define FTC_IMAGENODE_GET_GINDEX(n) FTC_PTR_TO_GINDEX((n)->root2.data) +#define FTC_IMAGENODE_GET_QINDEX(n) FTC_PTR_TO_QINDEX((n)->root2.data) +#define FTC_IMAGENODE_SET_INDICES(g,q) \ + do { (n)->root2.data = FTC_INDICES_TO_PTR(g,q); } while (0) + + + typedef struct FTC_Image_CacheRec_ + { + FTC_Manager manager; + FT_Memory memory; + + FT_ULong max_bytes; /* maximum size of cache in bytes */ + FT_ULong num_bytes; /* current size of cache in bytes */ + + FT_Lru queues_lru; /* static queues lru list */ + + } FTC_Image_Cache; + + + /* a table of functions used to generate/manager glyph images */ + typedef struct FTC_Image_Class_ + { + FT_Error (*init_image)( FTC_Image_Queue queue, + FTC_Image_Node node ); + + void (*done_image)( FTC_Image_Queue queue, + FTC_Image_Node node ); + + FT_ULong (*size_image)( FTC_Image_Queue queue, + FTC_Image_Node node ); + + } FTC_Image_Class; + + + typedef struct FTC_Image_QueueRec_ + { + FTC_Image_Cache cache; + FTC_Manager manager; + FT_Memory memory; + FTC_Image_Class* clazz; + FTC_Image_Desc descriptor; + FT_UInt hash_size; + FT_List buckets; + + } FTC_Image_SubCacheRec; + + + FT_EXPORT_DEF(FT_Error) FTC_Image_Cache_New( FTC_Manager manager, + FT_ULong max_bytes, + FTC_Image_Cache *acache ); + + FT_EXPORT_DEF(void) FTC_Image_Cache_Done( FTC_Image_Cache cache ); + + FT_EXPORT_DEF(FT_Error) FTC_Image_Cache_Lookup( FTC_Image_Cache cache, + FTC_Image_Desc* desc, + FT_UInt gindex, + FT_Glyph *aglyph ); + +#endif /* FTCIMAGE_H */ diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c new file mode 100644 index 000000000..98453e1ca --- /dev/null +++ b/src/cache/ftcmanag.c @@ -0,0 +1,280 @@ +#include +#include + +#define FTC_LRU_GET_MANAGER(lru) ((FTC_Manager_Lru)lru)->manager + + /*******************************************************************/ + /*******************************************************************/ + /***** *****/ + /***** FACE & SIZE LRU CALLBACKS *****/ + /***** *****/ + /*******************************************************************/ + /*******************************************************************/ + + static + FT_Error ftc_manager_init_face( FT_Lru lru, + FT_LruNode node ) + { + FTC_Manager manager = FTC_LRU_GET_MANAGER(lru); + FT_Error error; + + error = manager->request_face( (FTC_FaceID)node->key, + manager->request_data, + (FT_Face*)&node->root.data ); + if (!error) + { + /* destroy initial size object, it will be re-created later */ + FT_Face face = (FT_Face)node->root.data; + FT_Done_Size( face->size ); + } + return error; + } + + + /* helper function for ftc_manager_done_face */ + static + FT_Bool ftc_manager_size_selector( FT_Lru lru, + FT_LruNode node, + FT_Pointer data ) + { + FT_UNUSED(lru); + return ((FT_Size)node->root.data)->face == (FT_Face)data; + } + + static + void ftc_manager_done_face( FT_Lru lru, + FT_LruNode node ) + { + FTC_Manager manager = FTC_LRU_GET_MANAGER(lru); + FT_Face face = (FT_Face)node->root.data; + + /* we must begin by removing all sizes for the target face */ + /* from the manager's list.. */ + FT_Lru_Remove_Selection( manager->sizes_lru, + ftc_manager_size_selector, + face ); + + /* all right, we can discard the face now */ + FT_Done_Face( face ); + node->root.data = 0; + } + + + typedef struct FTC_SizeRequest_ + { + FT_Face face; + FT_UShort width; + FT_UShort height; + + } FTC_SizeRequest; + + + static + FT_Error ftc_manager_init_size( FT_Lru lru, + FT_LruNode node ) + { + FTC_SizeRequest* size_req = (FTC_SizeRequest*)node->key; + FT_Size size; + FT_Error error; + + FT_UNUSED(lru); + + node->root.data = 0; + error = FT_New_Size( size_req->face, &size ); + if (!error) + { + error = FT_Set_Pixel_Sizes( size_req->face, + size_req->width, + size_req->height ); + if (error) + FT_Done_Size(size); + else + node->root.data = size; + } + return error; + } + + + static + void ftc_manager_done_size( FT_Lru lru, + FT_LruNode node ) + { + FT_UNUSED(lru); + FT_Done_Size( (FT_Size)node->root.data ); + } + + + + static + FT_Error ftc_manager_flush_size( FT_Lru lru, + FT_LruNode node, + FT_LruKey key ) + { + FTC_SizeRequest* req = (FTC_SizeRequest*)key; + FT_Size size = (FT_Size)node->root.data; + FT_Error error; + + if ( size->face == req->face ) + { + size->face->size = size; /* set current size */ + error = FT_Set_Pixel_Sizes( req->face, req->width, req->height ); + if (error) + FT_Done_Size( size ); + } + else + { + FT_Done_Size(size); + node->key = key; + error = ftc_manager_init_size( lru, node ); + } + return error; + } + + + static + FT_Bool ftc_manager_compare_size( FT_LruNode node, + FT_LruKey key ) + { + FTC_SizeRequest* req = (FTC_SizeRequest*)key; + FT_Size size = (FT_Size)node->root.data; + + FT_UNUSED(node); + return ( size->face == req->face && + size->metrics.x_ppem == req->width && + size->metrics.y_ppem == req->height ); + } + + + + + static + const FT_Lru_Class ftc_face_lru_class = + { + sizeof( FTC_Manager_LruRec ), + ftc_manager_init_face, + ftc_manager_done_face, + 0, + 0 + }; + + + static + const FT_Lru_Class ftc_size_lru_class = + { + sizeof( FTC_Manager_LruRec ), + ftc_manager_init_size, + ftc_manager_done_size, + ftc_manager_flush_size, + ftc_manager_compare_size + }; + + + + FT_EXPORT_FUNC(FT_Error) FTC_Manager_New ( FT_Library library, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ) + { + FT_Error error; + FT_Memory memory = library->memory; + FTC_Manager manager = 0; + + + if ( ALLOC( manager, sizeof(*manager) ) ) + goto Exit; + + error = FT_Lru_New( &ftc_face_lru_class, + FTC_MAX_FACES, + memory, + 1, /* pre_alloc = TRUE */ + (FT_Lru*)&manager->faces_lru ); + if (error) + goto Exit; + + error = FT_Lru_New( &ftc_size_lru_class, + FTC_MAX_SIZES, + memory, + 1, /* pre_alloc = TRUE */ + (FT_Lru*)&manager->sizes_lru ); + if (error) + goto Exit; + + ((FTC_Manager_Lru)manager->faces_lru)->manager = manager; + ((FTC_Manager_Lru)manager->sizes_lru)->manager = manager; + + manager->library = library; + manager->request_face = requester; + manager->request_data = req_data; + *amanager = manager; + + Exit: + if (error && manager) + { + FT_Lru_Done( manager->sizes_lru ); + FT_Lru_Done( manager->faces_lru ); + FREE( manager ); + } + + return error; + } + + FT_EXPORT_DEF(void) FTC_Manager_Done ( FTC_Manager manager ) + { + FT_Memory memory = manager->library->memory; + + FT_Lru_Done( manager->sizes_lru ); + FT_Lru_Done( manager->faces_lru ); + FREE( manager ); + } + + + FT_EXPORT_DEF(void) FTC_Manager_Reset( FTC_Manager manager ) + { + FT_Lru_Reset( manager->sizes_lru ); + FT_Lru_Reset( manager->faces_lru ); + } + + + FT_EXPORT_DEF(FT_Error) FTC_Manager_Lookup_Face( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ) + { + return FT_Lru_Lookup( manager->faces_lru, + (FT_LruKey)face_id, + (FT_Pointer*)aface ); + } + + + + FT_EXPORT_DEF(FT_Error) FTC_Manager_Lookup_Size( FTC_Manager manager, + FTC_SizeID size_id, + FT_Face *aface, + FT_Size *asize ) + { + FTC_SizeRequest req; + FT_Error error; + FT_Face face; + + *aface = 0; + *asize = 0; + error = FTC_Manager_Lookup_Face( manager, size_id->face_id, &face ); + if (!error) + { + req.face = face; + req.width = size_id->pix_width; + req.height = size_id->pix_height; + + error = FT_Lru_Lookup( manager->sizes_lru, + (FT_LruKey)&req, + (FT_Pointer*)asize ); + if (!error) + { + /* select the size as the current one for this face */ + face->size = *asize; + *aface = face; + } + } + return error; + } + + diff --git a/src/cache/ftcmanag.h b/src/cache/ftcmanag.h new file mode 100644 index 000000000..e000e0900 --- /dev/null +++ b/src/cache/ftcmanag.h @@ -0,0 +1,65 @@ +#ifndef FTCMANAG_H +#define FTCMANAG_H + +#include + +#define FTC_MAX_FACES 4 +#define FTC_MAX_SIZES 8 + + typedef FT_Pointer FTC_FaceID; + + typedef struct FTC_SizeRec_ + { + FTC_FaceID face_id; + FT_UShort pix_width; + FT_UShort pix_height; + + } FTC_SizeRec, *FTC_SizeID; + + + typedef FT_Error (*FTC_Face_Requester)( FTC_FaceID face_id, + FT_Pointer data, + FT_Face *aface ); + + + typedef struct FTC_ManagerRec_* FTC_Manager; + + typedef struct FTC_Manager_LruRec_ + { + FT_LruRec root; + FTC_Manager manager; + + } FTC_Manager_LruRec, *FTC_Manager_Lru; + + + typedef struct FTC_ManagerRec_ + { + FT_Library library; + FT_Lru faces_lru; + FT_Lru sizes_lru; + + FT_Pointer request_data; + FTC_Face_Requester request_face; + + } FTC_ManagerRec; + + + FT_EXPORT_DEF(FT_Error) FTC_Manager_New ( FT_Library library, + FTC_Face_Requester requester, + FT_Pointer req_data, + FTC_Manager *amanager ); + + FT_EXPORT_DEF(void) FTC_Manager_Done ( FTC_Manager manager ); + + FT_EXPORT_DEF(void) FTC_Manager_Reset( FTC_Manager manager ); + + FT_EXPORT_DEF(FT_Error) FTC_Manager_Lookup_Face( FTC_Manager manager, + FTC_FaceID face_id, + FT_Face *aface ); + + FT_EXPORT_DEF(FT_Error) FTC_Manager_Lookup_Size( FTC_Manager manager, + FTC_SizeID size_id, + FT_Face *aface, + FT_Size *asize ); + +#endif /* FTCMANAG_H */ diff --git a/src/cache/ftlru.c b/src/cache/ftlru.c new file mode 100644 index 000000000..d9a619ac0 --- /dev/null +++ b/src/cache/ftlru.c @@ -0,0 +1,263 @@ +#include +#include +#include + + static + void lru_build_free_list( FT_LruNode nodes, + FT_UInt count, + FT_List free_list ) + { + FT_LruNode node = nodes; + FT_LruNode limit = node + count; + + free_list->head = free_list->tail = 0; + for ( ; node < limit; node++ ) + FT_List_Add( free_list, (FT_ListNode)node ); + } + + + FT_EXPORT_FUNC(FT_Error) FT_Lru_New ( const FT_Lru_Class* clazz, + FT_UInt max_elements, + FT_Memory memory, + FT_Bool pre_alloc, + FT_Lru *alru ) + { + FT_Error error; + FT_Lru lru; + + *alru = 0; + if ( !ALLOC( lru, sizeof(*lru) ) ) + { + if (pre_alloc) + { + /* allocate static array of lru list nodes */ + if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) ) + { + FREE( lru ); + goto Exit; + } + + /* build the 'free_nodes' list from the array */ + lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes ); + } + + /* initialize common fields */ + lru->clazz = (FT_Lru_Class*)clazz; + lru->max_elements = max_elements; + lru->memory = memory; + *alru = lru; + } + Exit: + return error; + } + + + + FT_EXPORT_DEF(void) FT_Lru_Reset ( FT_Lru lru ) + { + FT_ListNode node = lru->elements.head; + FT_Lru_Class* clazz = lru->clazz; + FT_Memory memory = lru->memory; + + while (node) + { + FT_ListNode next = node->next; + + clazz->done_element( lru, (FT_LruNode)node ); + if (!lru->nodes) + FREE(node); + + node = next; + } + + /* rebuild free list if necessary */ + if (lru->nodes) + lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes ); + lru->elements.head = lru->elements.tail = 0; + lru->num_elements = 0; + } + + + + FT_EXPORT_DEF(void) FT_Lru_Done ( FT_Lru lru ) + { + FT_Memory memory = lru->memory; + + FT_Lru_Reset(lru); + FREE(lru); + } + + + + FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup_Node( FT_Lru lru, + FT_LruKey key, + FT_LruNode* anode ) + { + FT_Error error = 0; + FT_ListNode node = lru->elements.head; + FT_Lru_Class* clazz = lru->clazz; + FT_LruNode found = 0; + FT_Memory memory = lru->memory; + + if (clazz->compare_element) + { + for ( ; node; node = node->next ) + if (clazz->compare_element( (FT_LruNode)node, key )) + { + found = (FT_LruNode)node; + break; + } + } + else + { + for ( ; node; node = node->next ) + if (((FT_LruNode)node)->key == key) + { + found = (FT_LruNode)node; + break; + } + } + + if (!found) + { + /* we didn't find the relevant element. We will now try */ + /* to create a new one.. */ + if ( lru->num_elements >= lru->max_elements ) + { + /* this lru list is full, we will now flush */ + /* the oldest node */ + FT_LruNode lru_node; + + + node = lru->elements.tail; + lru_node = (FT_LruNode)node; + + if (clazz->flush_element) + error = clazz->flush_element( lru, lru_node, key ); + else + { + clazz->done_element( lru, lru_node ); + lru_node->key = key; + node->data = 0; + error = clazz->init_element( lru, lru_node ); + } + + if (!error) + { + /* now, move element to top of list */ + FT_List_Up( &lru->elements, node ); + } + else + { + /* in case of error, the node must be discarded */ + FT_List_Remove( &lru->elements, node ); + lru->num_elements--; + + if (lru->nodes) + FT_List_Insert( &lru->free_nodes, node ); + else + FREE( lru_node ); + } + } + else + { + FT_LruNode lru_node; + + /* create a new lru list node, then the element for it */ + if (lru->nodes) + { + node = lru->free_nodes.head; + lru_node = (FT_LruNode)node; + lru_node->key = key; + + error = clazz->init_element( lru, lru_node ); + if (error) + goto Exit; + + FT_List_Remove( &lru->free_nodes, node ); + } + else + { + if ( ALLOC( lru_node, sizeof(*lru_node) ) ) + goto Exit; + + lru_node->key = key; + error = clazz->init_element( lru, lru_node ); + if (error) + { + FREE( lru_node ); + goto Exit; + } + } + + found = lru_node; + node = (FT_ListNode)lru_node; + FT_List_Insert( &lru->elements, node ); + lru->num_elements++; + } + } + + Exit: + *anode = found; + return error; + } + + + FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup( FT_Lru lru, + FT_LruKey key, + FT_Pointer *aobject ) + { + FT_Error error; + FT_LruNode node; + + *aobject = 0; + error = FT_Lru_Lookup_Node( lru, key, &node ); + if (!error) + *aobject = node->root.data; + + return error; + } + + + FT_EXPORT_FUNC(void) FT_Lru_Remove_Node( FT_Lru lru, + FT_LruNode node ) + { + if (lru->num_elements > 0) + { + FT_List_Remove( &lru->elements, (FT_ListNode)node ); + lru->clazz->done_element( lru, node ); + + if (lru->nodes) + FT_List_Insert( &lru->free_nodes, (FT_ListNode)node ); + else + { + FT_Memory memory = lru->memory; + FREE(node); + } + lru->num_elements--; + } + } + + + FT_EXPORT_FUNC(void) FT_Lru_Remove_Selection( FT_Lru lru, + FT_Lru_Selector selector, + FT_Pointer data ) + { + if (lru->num_elements > 0) + { + FT_ListNode node = lru->elements.head; + FT_ListNode next; + + while (node) + { + next = node->next; + if ( selector( lru, (FT_LruNode)node, data ) ) + { + /* remove this element from the list, and destroy it */ + FT_Lru_Remove_Node( lru, (FT_LruNode)node ); + } + node = next; + } + } + } + diff --git a/src/cache/ftlru.h b/src/cache/ftlru.h new file mode 100644 index 000000000..c61f89bfc --- /dev/null +++ b/src/cache/ftlru.h @@ -0,0 +1,83 @@ +#ifndef FTLRU_H +#define FTLRU_H + +#include + + + typedef FT_Pointer FT_LruKey; + + + typedef struct FT_LruNodeRec_ + { + FT_ListNodeRec root; + FT_LruKey key; + + } FT_LruNodeRec, *FT_LruNode; + + + typedef struct FT_LruRec_* FT_Lru; + + typedef struct FT_Lru_Class_ + { + FT_UInt lru_size; /* object size in bytes */ + + FT_Error (*init_element)( FT_Lru lru, + FT_LruNode node ); + + void (*done_element)( FT_Lru lru, + FT_LruNode node ); + + FT_Error (*flush_element)( FT_Lru lru, + FT_LruNode node, + FT_LruKey new_key ); + + FT_Bool (*compare_element)( FT_LruNode node, + FT_LruKey key ); + } FT_Lru_Class; + + + typedef FT_Bool (*FT_Lru_Selector)( FT_Lru lru, + FT_LruNode node, + FT_Pointer data ); + + typedef struct FT_LruRec_ + { + FT_Lru_Class* clazz; + FT_UInt max_elements; + FT_UInt num_elements; + FT_ListRec elements; + FT_Memory memory; + + /* the following fields are only meaningful for static lru containers */ + FT_ListRec free_nodes; + FT_LruNode nodes; + + } FT_LruRec; + + + FT_EXPORT_DEF(FT_Error) FT_Lru_New ( const FT_Lru_Class* clazz, + FT_UInt max_elements, + FT_Memory memory, + FT_Bool pre_alloc, + FT_Lru *alru ); + + FT_EXPORT_DEF(void) FT_Lru_Reset ( FT_Lru lru ); + + FT_EXPORT_DEF(void) FT_Lru_Done ( FT_Lru lru ); + + FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup_Node( FT_Lru lru, + FT_LruKey key, + FT_LruNode* anode ); + + FT_EXPORT_DEF(FT_Error) FT_Lru_Lookup( FT_Lru lru, + FT_LruKey key, + FT_Pointer *aobject ); + + FT_EXPORT_DEF(void) FT_Lru_Remove_Node( FT_Lru lru, + FT_LruNode node ); + + FT_EXPORT_DEF(void) FT_Lru_Remove_Selection( FT_Lru lru, + FT_Lru_Selector selector, + FT_Pointer data ); + +#endif /* FTLRU_H */