_major_ re-design of the caching sub-system. Still using the same API
though :-)
diff --git a/ChangeLog b/ChangeLog
index 50a559d..a9421d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2001-10-26  David Turner       <david@freetype.org>
+
+        * include/freetype/ftcache.h, include/freetype/cache/*.h,
+        src/cache/*.c: Major re-design of the cache sub-system to provide
+        better performance as well as an "Acquire"/"Release" API..
+        
+        seems to work well here.. but probably needs a bit more testing..
+        
+
 2001-10-26  Leonard Rosenthol  <leonardr@lazerware.com>
 
 	* updated Mac OS README (builds/mac/) to reflect my taking over
diff --git a/include/freetype/cache/ftcchunk.h b/include/freetype/cache/ftcchunk.h
index 47fed6e..e799123 100644
--- a/include/freetype/cache/ftcchunk.h
+++ b/include/freetype/cache/ftcchunk.h
@@ -60,109 +60,57 @@
 
   typedef struct FTC_ChunkNodeRec_*    FTC_ChunkNode;
   typedef struct FTC_ChunkSetRec_*     FTC_ChunkSet;
-  typedef struct FTC_Chunk_CacheRec_*  FTC_Chunk_Cache;
+  typedef struct FTC_ChunkCacheRec_*   FTC_ChunkCache;
 
   typedef struct  FTC_ChunkNodeRec_
   {
-    FTC_CacheNodeRec  root;
-    FTC_ChunkSet      cset;
-    FT_UShort         cset_index;
-    FT_UShort         num_elements;
-    FT_Byte*          elements;
+    FTC_NodeRec   node;
+    FTC_ChunkSet  cset;
+    FT_UShort     item_count;
+    FT_UShort     item_start;
+    FT_Byte*      items;
 
   } FTC_ChunkNodeRec;
 
+#define FTC_CHUNK_NODE(x)  ((FTC_ChunkNode)(x))
 
-#define FTC_CHUNKNODE_TO_LRUNODE( x )  ((FT_ListNode)( x ))
-#define FTC_LRUNODE_TO_CHUNKNODE( x )  ((FTC_ChunkNode)( x ))
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /*  chunk set methods                                                    */
-  /*                                                                       */
-
-  /* used to set "element_max", "element_count" and "element_size" */
-  typedef FT_Error
-  (*FTC_ChunkSet_SizesFunc)( FTC_ChunkSet  cset,
-                             FT_Pointer    type );
-
-  typedef FT_Error
-  (*FTC_ChunkSet_InitFunc)( FTC_ChunkSet  cset,
-                            FT_Pointer    type );
-
-  typedef void
-  (*FTC_ChunkSet_DoneFunc)( FTC_ChunkSet  cset );
-
-  typedef FT_Bool
-  (*FTC_ChunkSet_CompareFunc)( FTC_ChunkSet  cset,
-                               FT_Pointer    type );
-
-
-  typedef FT_Error
-  (*FTC_ChunkSet_NewNodeFunc)( FTC_ChunkSet    cset,
-                               FT_UInt         index,
-                               FTC_ChunkNode*  anode );
-
-  typedef void
-  (*FTC_ChunkSet_DestroyNodeFunc)( FTC_ChunkNode   node );
-
-  typedef FT_ULong
-  (*FTC_ChunkSet_SizeNodeFunc)( FTC_ChunkNode   node );
-
-
-  typedef struct  FTC_ChunkSet_Class_
+ /* a chunk set is used to categorize chunks of a given type */
+  typedef struct FTC_ChunkSetRec_
   {
-    FT_UInt                       cset_byte_size;
-
-    FTC_ChunkSet_InitFunc         init;
-    FTC_ChunkSet_DoneFunc         done;
-    FTC_ChunkSet_CompareFunc      compare;
-    FTC_ChunkSet_SizesFunc        sizes;
-
-    FTC_ChunkSet_NewNodeFunc      new_node;
-    FTC_ChunkSet_SizeNodeFunc     size_node;
-    FTC_ChunkSet_DestroyNodeFunc  destroy_node;
-
-  } FTC_ChunkSet_Class;
-
-
-  typedef struct  FTC_ChunkSetRec_
-  {
-    FTC_Chunk_Cache      cache;
-    FTC_Manager          manager;
-    FT_Memory            memory;
-    FTC_ChunkSet_Class*  clazz;
-    FT_UInt              cset_index;     /* index in parent cache    */
-
-    FT_UInt              element_max;    /* maximum number of elements   */
-    FT_UInt              element_size;   /* element size in bytes        */
-    FT_UInt              element_count;  /* number of elements per chunk */
-
-    FT_UInt              num_chunks;
-    FTC_ChunkNode*       chunks;
-
+    FT_LruNodeRec    lru;
+    FT_UFast         hash;
+    FTC_ChunkCache   ccache;
+    FT_Fast          num_chunks;
+    FT_UInt          item_total;   /* total number of glyphs in set   */
+    FT_UInt          item_size;    /* size of each glyph item in set  */
+    FT_UInt          item_count;   /* number of glyph items per chunk */
+  
   } FTC_ChunkSetRec;
 
+#define  FTC_CHUNK_SET(x)  ((FTC_ChunkSet)(x))
 
-  /* the abstract chunk cache class */
-  typedef struct  FTC_Chunk_Cache_Class_
+#define  FTC_CHUNK_SET_MEMORY(x)  ((x)->ccache->cache.memory)
+
+ /* the abstract chunk cache class */
+  typedef struct FTC_ChunkCacheRec_
   {
-    FTC_Cache_Class      root;
-    FTC_ChunkSet_Class*  cset_class;
+    FTC_CacheRec   cache;
+    FT_LruList     cset_lru;  /* LRU list of chunk sets */
+  
+  } FTC_ChunkCacheRec;
 
-  } FTC_Chunk_Cache_Class;
+#define  FTC_CHUNK_CACHE(x)  ((FTC_ChunkCache)(x))
 
 
-  /* the abstract chunk cache object */
-  typedef struct  FTC_Chunk_CacheRec_
+  typedef struct FTC_ChunkQueryRec_
   {
-    FTC_CacheRec              root;
-    FT_Lru                    csets_lru;   /* static chunk set lru list */
-    FTC_ChunkSet              last_cset;   /* small cache :-)           */
-    FTC_ChunkSet_CompareFunc  compare;     /* useful shortcut           */
+   /* input */
+    FT_UInt       gindex;      /* glyph index */
 
-  } FTC_Chunk_CacheRec;
+   /* output */
+    FTC_ChunkSet  cset;
+  
+  } FTC_ChunkQueryRec, *FTC_ChunkQuery;
 
 
   /*************************************************************************/
@@ -173,52 +121,44 @@
   /*                                                                       */
 
   FT_EXPORT( FT_Error )
-  FTC_ChunkNode_Init( FTC_ChunkNode  node,
-                      FTC_ChunkSet   cset,
-                      FT_UInt        index,
-                      FT_Bool        alloc );
-
-#define FTC_ChunkNode_Ref( n ) \
-          FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count++
-
-#define FTC_ChunkNode_Unref( n ) \
-          FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count--
-
+  ftc_chunk_node_init( FTC_ChunkNode  node,
+                       FTC_ChunkSet   cset,
+                       FT_UInt        index,
+                       FT_Bool        alloc );
 
   /* chunk set objects */
 
   FT_EXPORT( void )
-  FTC_ChunkNode_Destroy( FTC_ChunkNode    node );
+  ftc_chunk_node_done( FTC_ChunkNode  node );
 
 
   FT_EXPORT( FT_Error )
-  FTC_ChunkSet_New( FTC_Chunk_Cache  cache,
-                    FT_Pointer       type,
-                    FTC_ChunkSet    *aset );
+  ftc_chunk_set_init( FTC_ChunkSet    cset,
+                      FT_UInt         item_size,
+                      FT_UInt         item_count,
+                      FT_UInt         item_total,
+                      FTC_ChunkCache  cache );
 
-
-  FT_EXPORT( FT_Error )
-  FTC_ChunkSet_Lookup_Node( FTC_ChunkSet    cset,
-                            FT_UInt         glyph_index,
-                            FTC_ChunkNode*  anode,
-                            FT_UInt        *anindex );
+  FT_EXPORT( void )
+  ftc_chunk_set_done( FTC_ChunkSet  cset );
 
 
   /* chunk cache objects */
 
   FT_EXPORT( FT_Error )
-  FTC_Chunk_Cache_Init( FTC_Chunk_Cache  cache );
+  ftc_chunk_cache_init( FTC_ChunkCache    cache,
+                        FT_LruList_Class  cset_class );
 
   FT_EXPORT( void )
-  FTC_Chunk_Cache_Done( FTC_Chunk_Cache  cache );
+  ftc_chunk_cache_done( FTC_ChunkCache  cache );
+
 
   FT_EXPORT( FT_Error )
-  FTC_Chunk_Cache_Lookup( FTC_Chunk_Cache  cache,
-                          FT_Pointer       type,
-                          FT_UInt          gindex,
-                          FTC_ChunkNode   *anode,
-                          FT_UInt         *aindex );
+  ftc_chunk_cache_lookup( FTC_ChunkCache  cache,
+                          FTC_ChunkQuery  query,
+                          FTC_ChunkNode  *anode );
 
+ /* */
 
 FT_END_HEADER
 
diff --git a/include/freetype/cache/ftcglyph.h b/include/freetype/cache/ftcglyph.h
index a8af44a..c92e4fa 100644
--- a/include/freetype/cache/ftcglyph.h
+++ b/include/freetype/cache/ftcglyph.h
@@ -64,107 +64,83 @@
 FT_BEGIN_HEADER
 
 
-  /* maximum number of glyph sets per glyph cache; must be < 256 */
-#define FTC_MAX_GLYPH_SETS          16
-#define FTC_GSET_HASH_SIZE_DEFAULT  64
-
-
+ /* each glyph set is caracterized by a "glyph set type" which must be */
+ /* defined by sub-classes..                                           */
   typedef struct FTC_GlyphSetRec_*     FTC_GlyphSet;
-  typedef struct FTC_GlyphNodeRec_*    FTC_GlyphNode;
-  typedef struct FTC_Glyph_CacheRec_*  FTC_Glyph_Cache;
 
-  typedef struct  FTC_GlyphNodeRec_
+ /* handle to a glyph cache node */
+  typedef struct FTC_GlyphNodeRec_*    FTC_GlyphNode;
+
+ /* a glyph cache, its nodes are all glyph-specific */
+  typedef struct FTC_GlyphCacheRec_*   FTC_GlyphCache;
+
+ /* glyph sets class handle */
+  typedef const struct FTC_GlyphSet_ClassRec_*   FTC_GlyphSet_Class;
+
+
+ /* size should be 24 bytes on 32-bit machines                      */
+ /* note that the node's hash is ((gset->hash << 16) | glyph_index) */
+ /* this _must_ be set properly by the glyph node initializer       */
+ /*                                                                 */
+  typedef struct FTC_GlyphNodeRec_
   {
-    FTC_CacheNodeRec  root;
-    FTC_GlyphNode     gset_next;   /* next in glyph set's bucket list */
-    FT_UShort         glyph_index;
-    FT_UShort         gset_index;
+    FTC_NodeRec     node;
+    FTC_GlyphSet    gset;
 
   } FTC_GlyphNodeRec;
 
-
-#define FTC_GLYPHNODE( x )             ( (FTC_GlyphNode)( x ) )
-#define FTC_GLYPHNODE_TO_LRUNODE( n )  ( (FT_ListNode)( n ) )
-#define FTC_LRUNODE_TO_GLYPHNODE( n )  ( (FTC_GlyphNode)( n ) )
+#define  FTC_GLYPH_NODE(x)    ((FTC_GlyphNode)(x))
+#define  FTC_GLYPH_NODE_P(x)  ((FTC_GlyphNode*)(x))
 
 
-  /*************************************************************************/
-  /*                                                                       */
-  /* Glyph set methods.                                                    */
-  /*                                                                       */
-
-  typedef FT_Error
-  (*FTC_GlyphSet_InitFunc)( FTC_GlyphSet    gset,
-                            FT_Pointer      type );
-
-  typedef void
-  (*FTC_GlyphSet_DoneFunc)( FTC_GlyphSet    gset );
-
-  typedef FT_Bool
-  (*FTC_GlyphSet_CompareFunc)( FTC_GlyphSet    gset,
-                               FT_Pointer      type );
-
-
-  typedef FT_Error
-  (*FTC_GlyphSet_NewNodeFunc)( FTC_GlyphSet    gset,
-                               FT_UInt         gindex,
-                               FTC_GlyphNode*  anode );
-
-  typedef void
-  (*FTC_GlyphSet_DestroyNodeFunc)( FTC_GlyphNode   node,
-                                   FTC_GlyphSet    gset );
-
-  typedef FT_ULong
-  (*FTC_GlyphSet_SizeNodeFunc)( FTC_GlyphNode   node,
-                                FTC_GlyphSet    gset );
-
-
-  typedef struct  FTC_GlyphSet_Class_
-  {
-    FT_UInt                       gset_byte_size;
-
-    FTC_GlyphSet_InitFunc         init;
-    FTC_GlyphSet_DoneFunc         done;
-    FTC_GlyphSet_CompareFunc      compare;
-
-    FTC_GlyphSet_NewNodeFunc      new_node;
-    FTC_GlyphSet_SizeNodeFunc     size_node;
-    FTC_GlyphSet_DestroyNodeFunc  destroy_node;
-
-  } FTC_GlyphSet_Class;
-
-
+ /* the glyph set structure. each glyph set is used to model a set of     */
+ /* glyphs of the same "type". The type itself is defined in sub-classes  */
+ /*                                                                       */
+ /* for example, the "image cache" uses face_id + character_pixel_sizes + */
+ /* image_format to characterize glyph sets..                             */
+ /*                                                                       */
+ /* a pure "master outlines" cache would only use face_id, etc..          */
+ /*                                                                       */
   typedef struct  FTC_GlyphSetRec_
   {
-    FTC_Glyph_Cache      cache;
-    FTC_Manager          manager;
-    FT_Memory            memory;
-    FTC_GlyphSet_Class*  clazz;
-    FT_UInt              hash_size;
-    FTC_GlyphNode*       buckets;
-    FT_UInt              gset_index;  /* index in parent cache    */
+    FT_LruNodeRec   lru;         /* glyph sets are LRU nodes within */
+    FTC_GlyphCache  gcache;      /* parent cache..                  */
+    FT_UFast        hash;        /* must be set by initializer !!   */
+    FT_Fast         num_glyphs;  /* destroyed when 0..              */
 
   } FTC_GlyphSetRec;
 
+#define  FTC_GLYPH_SET(x)     ((FTC_GlyphSet)(x))
+#define  FTC_GLYPH_SET_P(x)   ((FTC_GlyphSet*)(x))
 
-  /* the abstract glyph cache class */
-  typedef struct  FTC_Glyph_Cache_Class_
-  {
-    FTC_Cache_Class      root;
-    FTC_GlyphSet_Class*  gset_class;
+#define  FTC_GLYPH_SET_MEMORY(x)  ((x)->gcache->cache.memory)
 
-  } FTC_Glyph_Cache_Class;
 
+/* retrieve glyph index of glyph node */
+#define  FTC_GLYPH_NODE_GINDEX(x)  \
+             ((FT_UInt)(FTC_GLYPH_NODE(x)->node.hash & 0xFFFF))
 
   /* the abstract glyph cache object */
-  typedef struct  FTC_Glyph_CacheRec_
+  typedef struct  FTC_GlyphCacheRec_
   {
-    FTC_CacheRec              root;
-    FT_Lru                    gsets_lru;    /* static sets lru list */
-    FTC_GlyphSet              last_gset;    /* small cache :-)      */
-    FTC_GlyphSet_CompareFunc  compare;      /* useful shortcut      */
+    FTC_CacheRec  cache;
+    FT_LruList    gset_lru;   /* LRU list of glyph sets */
 
-  } FTC_Glyph_CacheRec;
+  } FTC_GlyphCacheRec;
+
+#define  FTC_GLYPH_CACHE(x)    ((FTC_GlyphCache)(x))
+#define  FTC_GLYPH_CACHE_P(x)  ((FTC_GlyphCache*)(x))
+
+
+  typedef struct FTC_GlyphQueryRec_
+  {
+   /* input */
+    FT_UInt       gindex;
+   
+   /* output */
+    FTC_GlyphSet  gset;
+
+  } FTC_GlyphQueryRec, *FTC_GlyphQuery;
 
 
   /*************************************************************************/
@@ -174,44 +150,41 @@
   /* cache sub-system internals.                                           */
   /*                                                                       */
 
+ /* must be called by derived FTC_Node_InitFunc routines */
   FT_EXPORT( void )
-  FTC_GlyphNode_Init( FTC_GlyphNode  node,
-                      FTC_GlyphSet   gset,
-                      FT_UInt        gindex );
+  ftc_glyph_node_init( FTC_GlyphNode  node,
+                       FT_UInt        gindex,  /* glyph index for node */
+                       FTC_GlyphSet   gset );
 
-#define FTC_GlyphNode_Ref( n ) \
-          FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count++
-
-#define FTC_GlyphNode_Unref( n ) \
-          FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count--
-
-
+ /* must be called by derived FTC_Node_DoneFunc routines */
   FT_EXPORT( void )
-  FTC_GlyphNode_Destroy( FTC_GlyphNode    node,
-                         FTC_Glyph_Cache  cache );
+  ftc_glyph_node_done( FTC_GlyphNode  node );
 
+
+ /* can be used as a FTC_LruNode_InitFunc or called by sub-classes */
   FT_EXPORT( FT_Error )
-  FTC_Glyph_Cache_Init(  FTC_Glyph_Cache  cache );
+  ftc_glyph_set_init( FTC_GlyphSet  gset,
+                      FT_LruList    list );
 
+ /* can be used as a FTC_LruNode_DoneFunc or called by sub-classes */
   FT_EXPORT( void )
-  FTC_Glyph_Cache_Done(  FTC_Glyph_Cache  cache );
+  ftc_glyph_set_done( FTC_GlyphSet  gset );
 
 
+ /* can be used as a FTC_Cache_DoneFunc or called by sub-classes */
+  FT_EXPORT( void )
+  ftc_glyph_cache_done(  FTC_GlyphCache  cache );
+
+ /* must be called in a FTC_Cache_InitFunc !! */
   FT_EXPORT( FT_Error )
-  FTC_GlyphSet_New( FTC_Glyph_Cache  cache,
-                    FT_Pointer       type,
-                    FTC_GlyphSet    *aset );
+  ftc_glyph_cache_init( FTC_GlyphCache    cache,
+                        FT_LruList_Class  gset_class );
 
+ /* can be called directly or from sub-classes */
   FT_EXPORT( FT_Error )
-  FTC_GlyphSet_Lookup_Node( FTC_GlyphSet    gset,
-                            FT_UInt         glyph_index,
-                            FTC_GlyphNode  *anode );
-
-  FT_EXPORT( FT_Error )
-  FTC_Glyph_Cache_Lookup( FTC_Glyph_Cache  cache,
-                          FT_Pointer       type,
-                          FT_UInt          gindex,
-                          FTC_GlyphNode   *anode );
+  ftc_glyph_cache_lookup( FTC_GlyphCache  cache,
+                          FTC_GlyphQuery  query,
+                          FTC_GlyphNode  *anode );
 
 
 FT_END_HEADER
diff --git a/include/freetype/cache/ftcimage.h b/include/freetype/cache/ftcimage.h
index 376aeab..a82cf8a 100644
--- a/include/freetype/cache/ftcimage.h
+++ b/include/freetype/cache/ftcimage.h
@@ -29,7 +29,6 @@
 
 #include <ft2build.h>
 #include FT_CACHE_H
-#include FT_CACHE_INTERNAL_GLYPH_H
 
 
 FT_BEGIN_HEADER
@@ -96,6 +95,14 @@
 
   } FTC_Image_Desc;
 
+ /* */
+#define  FTC_IMAGE_DESC_COMPARE( d1, d2 )                        \
+             ( FTC_FONT_COMPARE( &(d1)->font, &(d2)->font ) &&   \
+               (d1)->image_type == (d2)->image_type         )
+
+#define  FTC_IMAGE_DESC_HASH(d)                         \
+             (FT_UFast)( FTC_FONT_HASH(&(d)->font) ^    \
+                         ((d)->image_type << 4)    )
 
   /*************************************************************************/
   /*                                                                       */
diff --git a/include/freetype/cache/ftcmanag.h b/include/freetype/cache/ftcmanag.h
index 2d97fad..0aa1086 100644
--- a/include/freetype/cache/ftcmanag.h
+++ b/include/freetype/cache/ftcmanag.h
@@ -81,12 +81,23 @@
 
 #define FTC_MAX_FACES_DEFAULT  2
 #define FTC_MAX_SIZES_DEFAULT  4
-#define FTC_MAX_BYTES_DEFAULT  200000L  /* 200kByte by default! */
+#define FTC_MAX_BYTES_DEFAULT  100000L  /* 200kByte by default! */
 
   /* maximum number of caches registered in a single manager */
 #define FTC_MAX_CACHES         16
 
 
+ /* handle to cache object */
+  typedef struct FTC_CacheRec_*  FTC_Cache;
+
+ /* handle to cache class */
+  typedef const struct FTC_Cache_ClassRec_*  FTC_Cache_Class;
+  
+ /* handle to cache node */
+  typedef struct FTC_NodeRec_*   FTC_Node;
+
+
+
   /*************************************************************************/
   /*                                                                       */
   /* <Struct>                                                              */
@@ -125,13 +136,15 @@
   typedef struct  FTC_ManagerRec_
   {
     FT_Library          library;
-    FT_Lru              faces_lru;
-    FT_Lru              sizes_lru;
+    FT_LruList          faces_list;
+    FT_LruList          sizes_list;
 
-    FT_ULong            max_bytes;
-    FT_ULong            num_bytes;
+    FT_ULong            max_weight;
+    FT_ULong            cur_weight;
+    
     FT_UInt             num_nodes;
-    FT_ListRec          global_lru;
+    FTC_Node            nodes_list;
+    
     FTC_Cache           caches[FTC_MAX_CACHES];
 
     FT_Pointer          request_data;
@@ -185,197 +198,135 @@
   /* glyphs for a given size, some metrics, etc.                           */
   /*                                                                       */
 
-  typedef FT_ListNodeRec     FTC_CacheNodeRec;
-  typedef FTC_CacheNodeRec*  FTC_CacheNode;
 
-
-  /* the field `cachenode.data' is typecast to this type */
-  typedef struct  FTC_CacheNode_Data_
+ /* structure size should be 20 bytes on 32-bits machines */  
+  typedef struct FTC_NodeRec_
   {
-    FT_UShort  cache_index;
-    FT_Short   ref_count;
+    FTC_Node   mru_next;     /* circular mru list pointer           */
+    FTC_Node   mru_prev;     /* circular mru list pointer           */
+    FTC_Node   link;         /* used for hashing..                  */
+    FT_UInt32  hash;         /* used for hashing too..              */
+    FT_UShort  cache_index;  /* index of cache this node belongs to */
+    FT_Short   ref_count;    /* reference count for this node..     */
+  
+  } FTC_NodeRec;
 
-  } FTC_CacheNode_Data;
+#define  FTC_NODE(x)    ((FTC_Node)(x))
+#define  FTC_NODE_P(x)  ((FTC_Node*)(x))
 
 
-  /* return a pointer to FTC_CacheNode_Data contained in a */
-  /* CacheNode's `data' field                              */
-#define FTC_CACHENODE_TO_DATA_P( n ) \
-          ( (FTC_CacheNode_Data*)&(n)->data )
-
-#define FTC_LIST_TO_CACHENODE( n )  ( (FTC_CacheNode)(n) )
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <FuncType>                                                            */
-  /*    FTC_CacheNode_SizeFunc                                             */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A function used to compute the total size in bytes of a given      */
-  /*    cache node.  It is used by the cache manager to compute the number */
-  /*    of old nodes to flush when the cache is full.                      */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    node       :: A handle to the target cache node.                   */
-  /*                                                                       */
-  /*    cache_data :: A generic pointer passed to the destructor.          */
-  /*                                                                       */
-  /* <Return>                                                              */
-  /*    The size of a given cache node in bytes.                           */
-  /*                                                                       */
-  typedef FT_ULong
-  (*FTC_CacheNode_SizeFunc)( FTC_CacheNode  node,
-                             FT_Pointer     cache_data );
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <FuncType>                                                            */
-  /*    FTC_CacheNode_DestroyFunc                                          */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A function used to destroy a given cache node.  It is called by    */
-  /*    the manager when the cache is full and old nodes need to be        */
-  /*    flushed out.                                                       */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    node       :: A handle to the target cache node.                   */
-  /*                                                                       */
-  /*    cache_data :: A generic pointer passed to the destructor.          */
-  /*                                                                       */
-  typedef void
-  (*FTC_CacheNode_DestroyFunc)( FTC_CacheNode  node,
-                                FT_Pointer     cache_data );
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Struct>                                                              */
-  /*    FTC_CacheNode_Class                                                */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A very simple structure used to describe a cache node's class to   */
-  /*    the cache manager.                                                 */
-  /*                                                                       */
-  /* <Fields>                                                              */
-  /*    size_node    :: A function used to size the node.                  */
-  /*                                                                       */
-  /*    destroy_node :: A function used to destroy the node.               */
-  /*                                                                       */
-  /* <Note>                                                                */
-  /*    The cache node class doesn't include a `new_node' function because */
-  /*    the cache manager never allocates cache node directly; it          */
-  /*    delegates this task to its cache objects.                          */
-  /*                                                                       */
-  typedef struct  FTC_CacheNode_Class_
-  {
-    FTC_CacheNode_SizeFunc     size_node;
-    FTC_CacheNode_DestroyFunc  destroy_node;
-
-  } FTC_CacheNode_Class;
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                       CACHE DEFINITIONS                       *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <FuncType>                                                            */
-  /*    FTC_Cache_InitFunc                                                 */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A function used to initialize a given cache object.                */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    cache :: A handle to the new cache.                                */
-  /*                                                                       */
-  typedef FT_Error
-  (*FTC_Cache_InitFunc)( FTC_Cache  cache );
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <FuncType>                                                            */
-  /*    FTC_Cache_DoneFunc                                                 */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A function to finalize a given cache object.                       */
-  /*                                                                       */
-  /* <Input>                                                               */
-  /*    cache :: A handle to the target cache.                             */
-  /*                                                                       */
-  typedef void
-  (*FTC_Cache_DoneFunc)( FTC_Cache  cache );
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Struct>                                                              */
-  /*    FTC_Cache_Class                                                    */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A structure used to describe a given cache object class to the     */
-  /*    cache manager.                                                     */
-  /*                                                                       */
-  /* <Fields>                                                              */
-  /*    cache_byte_size :: The size of the cache object in bytes.          */
-  /*                                                                       */
-  /*    init_cache      :: The cache object initializer.                   */
-  /*                                                                       */
-  /*    done_cache      :: The cache object finalizer.                     */
-  /*                                                                       */
-  struct  FTC_Cache_Class_
-  {
-    FT_UInt             cache_byte_size;
-    FTC_Cache_InitFunc  init_cache;
-    FTC_Cache_DoneFunc  done_cache;
-  };
-
-
-  /*************************************************************************/
-  /*                                                                       */
-  /* <Struct>                                                              */
-  /*    FTC_CacheRec                                                       */
-  /*                                                                       */
-  /* <Description>                                                         */
-  /*    A structure used to describe an abstract cache object.             */
-  /*                                                                       */
-  /* <Fields>                                                              */
-  /*    manager     :: A handle to the parent cache manager.               */
-  /*                                                                       */
-  /*    memory      :: A handle to the memory manager.                     */
-  /*                                                                       */
-  /*    clazz       :: A pointer to the cache class.                       */
-  /*                                                                       */
-  /*    node_clazz  :: A pointer to the cache's node class.                */
-  /*                                                                       */
-  /*    cache_index :: An index of the cache in the manager's table.       */
-  /*                                                                       */
-  /*    cache_data  :: Data passed to the cache node                       */
-  /*                   constructor/finalizer.                              */
-  /*                                                                       */
+ /* each cache really implements a dynamic hash table to manage its nodes */
   typedef struct  FTC_CacheRec_
   {
-    FTC_Manager           manager;
-    FT_Memory             memory;
-    FTC_Cache_Class*      clazz;
-    FTC_CacheNode_Class*  node_clazz;
+    FTC_Manager      manager;
+    FT_Memory        memory;
+    FTC_Cache_Class  clazz;
 
-    FT_UInt               cache_index;  /* in manager's table           */
-    FT_Pointer            cache_data;   /* passed to cache node methods */
+    FT_UInt          cache_index;  /* in manager's table         */
+    FT_Pointer       cache_data;   /* used by cache node methods */
+
+    FT_UFast         nodes;
+    FT_UFast         size;
+    FTC_Node*        buckets;
 
   } FTC_CacheRec;
 
 
+#define  FTC_CACHE(x)    ((FTC_Cache)(x))
+#define  FTC_CACHE_P(x)  ((FTC_Cache*)(x))
+
+
+ /* initialize a given cache */
+  typedef FT_Error
+  (*FTC_Cache_InitFunc)( FTC_Cache   cache );
+  
+ /* finalize a given cache */
+  typedef void
+  (*FTC_Cache_DoneFunc)( FTC_Cache   cache );
+
+ /* initialize a new cache node */
+  typedef FT_Error
+  (*FTC_Node_InitFunc)( FTC_Node    node,
+                        FT_Pointer  type,
+                        FTC_Cache   cache );
+
+ /* compute the weight of a given cache node */
+  typedef FT_ULong
+  (*FTC_Node_WeightFunc)( FTC_Node    node,
+                          FTC_Cache   cache );
+
+ /* compare a node to a given key pair */
+  typedef FT_Bool
+  (*FTC_Node_CompareFunc)( FTC_Node   node,
+                           FT_Pointer key,
+                           FTC_Cache  cache );
+
+ /* finalize a given cache node */
+  typedef void
+  (*FTC_Node_DoneFunc)( FTC_Node    node,
+                        FTC_Cache   cache );
+
+  typedef struct FTC_Cache_ClassRec_
+  {
+    FT_UInt               cache_size;
+    FTC_Cache_InitFunc    cache_init;
+    FTC_Cache_DoneFunc    cache_done;
+    
+    FT_UInt               node_size;
+    FTC_Node_InitFunc     node_init;
+    FTC_Node_WeightFunc   node_weight;
+    FTC_Node_CompareFunc  node_compare;
+    FTC_Node_DoneFunc     node_done;
+  
+  } FTC_Cache_ClassRec;
+
   /* */
 
+#define  FTC_CACHE_RESIZE_TEST(c)            \
+            ( (c)->nodes*3 < (c)->size  ||   \
+              (c)->size*3  < (c)->nodes )      
+
+
+  /* this must be used internally for the moment */
+  FT_EXPORT( FT_Error )
+  FTC_Manager_Register_Cache( FTC_Manager      manager,
+                              FTC_Cache_Class  clazz,
+                              FTC_Cache       *acache );
+
+
+ /* can be used directory as FTC_Cache_DoneFunc, or called by custom */
+ /* cache finalizers..                                               */
+  FT_EXPORT( void )
+  ftc_cache_done( FTC_Cache  cache );
+
+ /* initalize the hash table within the cache */
+  FT_EXPORT( FT_Error )
+  ftc_cache_init( FTC_Cache  cache );
+
+ /* can be used when FTC_CACHE_RESIZE_TEST returns TRUE after a node */
+ /* insertion..                                                      */
+  FT_EXPORT(void)
+  ftc_cache_resize( FTC_Cache  cache );
+
+
+ /* can be called when the key's hash value has been computed */
+  FT_EXPORT(FT_Error)
+  ftc_cache_lookup_node( FTC_Cache    cache,
+                         FT_UFast     key_hash,
+                         FT_Pointer   key,
+                         FTC_Node    *anode );
+
+ /* can be called to increment a node's reference count */
+  FT_EXPORT(void)
+  ftc_node_ref( FTC_Node   node,
+                FTC_Cache  cache );
+
+ /* can be called to decrement a node's reference count */
+  FT_EXPORT(void)
+  ftc_node_unref( FTC_Node   node,
+                  FTC_Cache  cache );
+
+ /* */
 
 FT_END_HEADER
 
diff --git a/include/freetype/cache/ftcsbits.h b/include/freetype/cache/ftcsbits.h
index aba87c8..1a30846 100644
--- a/include/freetype/cache/ftcsbits.h
+++ b/include/freetype/cache/ftcsbits.h
@@ -22,7 +22,6 @@
 
 #include <ft2build.h>
 #include FT_CACHE_H
-#include FT_CACHE_INTERNAL_CHUNK_H
 #include FT_CACHE_IMAGE_H
 
 
diff --git a/include/freetype/cache/ftlru.h b/include/freetype/cache/ftlru.h
index 7874438..27fdcf1 100644
--- a/include/freetype/cache/ftlru.h
+++ b/include/freetype/cache/ftlru.h
@@ -66,117 +66,130 @@
 FT_BEGIN_HEADER
 
 
-  /* generic key type */
+  /* generic list key type */
   typedef FT_Pointer  FT_LruKey;
 
+  /* a list list handle */
+  typedef struct FT_LruListRec_*  FT_LruList;
 
-  /* an lru node -- root.data points to the element */
+  /* list class handle */
+  typedef const struct FT_LruList_ClassRec_*   FT_LruList_Class;
+
+  /* an list node handle */
+  typedef struct  FT_LruNodeRec_*   FT_LruNode;
+  
+  /* the list node structure */
   typedef struct  FT_LruNodeRec_
   {
-    FT_ListNodeRec  root;
-    FT_LruKey       key;
+    FT_LruNode  next;
+    FT_LruKey   key;
 
-  } FT_LruNodeRec, *FT_LruNode;
+  } FT_LruNodeRec;
 
 
-  /* forward declaration */
-  typedef struct FT_LruRec_*  FT_Lru;
-
-
-  /* LRU class */
-  typedef struct  FT_Lru_Class_
+  /* the list structure */
+  typedef struct  FT_LruListRec_
   {
-    FT_UInt  lru_size;      /* object size in bytes */
+    FT_Memory          memory;
+    FT_LruList_Class   clazz;
+    FT_LruNode         nodes;
+    FT_UInt            max_nodes;
+    FT_UInt            num_nodes;
+    FT_Pointer         user_data;
 
-    /* this method is used to initialize a new list element node */
-    FT_Error
-    (*init_element)( FT_Lru      lru,
-                     FT_LruNode  node );
+  } FT_LruListRec;
 
-    /* this method is used to finalize a given list element node */
-    void
-    (*done_element)( FT_Lru      lru,
-                     FT_LruNode  node );
 
-    /* If defined, this method is called when the list if full        */
-    /* during the lookup process -- it is used to change the contents */
-    /* of a list element node, instead of calling `done_element()',   */
-    /* then `init_element'.  Set it to 0 for default behaviour.       */
-    FT_Error
-    (*flush_element)( FT_Lru      lru,
-                      FT_LruNode  node,
-                      FT_LruKey   new_key );
+ /* initialize a list list */
+  typedef FT_Error  (*FT_LruList_InitFunc)( FT_LruList  list );
+  
+ /* finalize a list list */
+  typedef void      (*FT_LruList_DoneFunc)( FT_LruList  list );
 
-    /* If defined, this method is used to compare a list element node */
-    /* with a given key during a lookup.  If set to 0, the `key'      */
-    /* fields will be directly compared instead.                      */
-    FT_Bool
-    (*compare_element)( FT_LruNode  node,
-                        FT_LruKey   key );
+ /* this method is used to initialize a new list element node */
+  typedef FT_Error  (*FT_LruNode_InitFunc)( FT_LruNode  node,
+                                            FT_LruKey   key,
+                                            FT_LruList  list );
 
-  } FT_Lru_Class;
+ /* this method is used to finalize a given list element node */
+  typedef void      (*FT_LruNode_DoneFunc)( FT_LruNode  node,
+                                            FT_LruList  list );
 
+ /* If defined, this method is called when the list if full        */
+ /* during the lookup process -- it is used to change the contents */
+ /* of a list element node, instead of calling `done_element()',   */
+ /* then `init_element'.  Set it to 0 for default behaviour.       */
+  typedef FT_Error  (*FT_LruNode_FlushFunc)( FT_LruNode  node,
+                                             FT_LruKey   new_key,
+                                             FT_LruList  list );
+
+ /* If defined, this method is used to compare a list element node */
+ /* with a given key during a lookup.  If set to 0, the `key'      */
+ /* fields will be directly compared instead.                      */
+  typedef FT_Bool   (*FT_LruNode_CompareFunc)( FT_LruNode  node,
+                                               FT_LruKey   key,
+                                               FT_LruList  list );
 
   /* A selector is used to indicate whether a given list element node    */
-  /* is part of a selection for FT_Lru_Remove_Selection().  The function */
+  /* is part of a selection for FT_LruList_Remove_Selection().  The function */
   /* must return true (i.e., non-null) to indicate that the node is part */
   /* of it.                                                              */
-  typedef FT_Bool
-  (*FT_Lru_Selector)( FT_Lru      lru,
-                      FT_LruNode  node,
-                      FT_Pointer  data );
+  typedef FT_Bool    (*FT_LruNode_SelectFunc)( FT_LruNode  node,
+                                               FT_Pointer  data,
+                                               FT_LruList  list );
 
-
-  typedef struct  FT_LruRec_
+  /* LRU class */
+  typedef struct  FT_LruList_ClassRec_
   {
-    FT_Lru_Class*  clazz;
-    FT_UInt        max_elements;
-    FT_UInt        num_elements;
-    FT_ListRec     elements;
-    FT_Memory      memory;
-    FT_Pointer     user_data;
+    FT_UInt                 list_size;
+    FT_LruList_InitFunc     list_init;      /* optional */
+    FT_LruList_DoneFunc     list_done;      /* optional */
+  
+    FT_UInt                 node_size;
+    FT_LruNode_InitFunc     node_init;     /* MANDATORY */
+    FT_LruNode_DoneFunc     node_done;     /* optional  */
+    FT_LruNode_FlushFunc    node_flush;    /* optional  */
+    FT_LruNode_CompareFunc  node_compare;  /* optional  */
 
-    /* the following fields are only meaningful for static lru containers */
-    FT_ListRec     free_nodes;
-    FT_LruNode     nodes;
+  } FT_LruList_ClassRec;
 
-  } FT_LruRec;
+
+ /* the following functions must be exported in the case where applications */
+ /* would want to write their own cache classes..                           */
+
+  FT_EXPORT( FT_Error )
+  FT_LruList_New( FT_LruList_Class  clazz,
+                  FT_UInt           max_elements,
+                  FT_Pointer        user_data,
+                  FT_Memory         memory,
+                  FT_LruList       *alist );
+
+  FT_EXPORT( void )
+  FT_LruList_Reset( FT_LruList  list );
+
+
+  FT_EXPORT( void )
+  FT_LruList_Destroy ( FT_LruList  list );
 
 
   FT_EXPORT( FT_Error )
-  FT_Lru_New( const FT_Lru_Class*  clazz,
-              FT_UInt              max_elements,
-              FT_Pointer           user_data,
-              FT_Memory            memory,
-              FT_Bool              pre_alloc,
-              FT_Lru              *anlru );
+  FT_LruList_Lookup( FT_LruList    list,
+                     FT_LruKey     key,
+                     FT_LruNode   *anode );
+
 
   FT_EXPORT( void )
-  FT_Lru_Reset( FT_Lru  lru );
+  FT_LruList_Remove( FT_LruList  list,
+                     FT_LruNode  node );
+
 
   FT_EXPORT( void )
-  FT_Lru_Done ( FT_Lru  lru );
+  FT_LruList_Remove_Selection( FT_LruList             list,
+                               FT_LruNode_SelectFunc  select_func,
+                               FT_Pointer             select_data );
 
-  FT_EXPORT( FT_Error )
-  FT_Lru_Lookup_Node( FT_Lru        lru,
-                      FT_LruKey     key,
-                      FT_LruNode   *anode );
-
-  FT_EXPORT( FT_Error )
-  FT_Lru_Lookup( FT_Lru       lru,
-                 FT_LruKey    key,
-                 FT_Pointer  *anobject );
-
-  FT_EXPORT( void )
-  FT_Lru_Remove_Node( FT_Lru      lru,
-                      FT_LruNode  node );
-
-  FT_EXPORT( void )
-  FT_Lru_Remove_Selection( FT_Lru           lru,
-                           FT_Lru_Selector  selector,
-                           FT_Pointer       data );
-
-
+ /* */
+ 
 FT_END_HEADER
 
 #endif /* __FTLRU_H__ */
diff --git a/include/freetype/ftcache.h b/include/freetype/ftcache.h
index fc15956..8fcbd19 100644
--- a/include/freetype/ftcache.h
+++ b/include/freetype/ftcache.h
@@ -142,6 +142,19 @@
 
   } FTC_FontRec;
 
+ /* */
+
+#define  FTC_FONT_COMPARE(f1,f2)                           \
+             ( (f1)->face_id    == (f2)->face_id    &&     \
+               (f1)->pix_width  == (f2)->pix_width  &&     \
+               (f1)->pix_height == (f2)->pix_height )
+
+#define  FTC_FACE_ID_HASH(i)   ((FT_UInt32)(FT_Pointer)(i))
+
+#define  FTC_FONT_HASH(f)                                   \
+             (FT_UInt32)( FTC_FACE_ID_HASH((f)->face_id) ^  \
+                          ((f)->pix_width << 8)          ^  \
+                          ((f)->pix_height)              )
 
   /*************************************************************************/
   /*                                                                       */
@@ -334,19 +347,6 @@
                            FT_Face     *aface,
                            FT_Size     *asize );
 
-
-  /* a cache class is used to describe a unique cache type to the manager */
-  typedef struct FTC_Cache_Class_  FTC_Cache_Class;
-  typedef struct FTC_CacheRec_*    FTC_Cache;
-
-
-  /* this must be used internally for the moment */
-  FT_EXPORT( FT_Error )
-  FTC_Manager_Register_Cache( FTC_Manager       manager,
-                              FTC_Cache_Class*  clazz,
-                              FTC_Cache        *acache );
-
-
   /* */
 
 
diff --git a/src/base/ftdbgmem.c b/src/base/ftdbgmem.c
index 048df3e..42ccc97 100644
--- a/src/base/ftdbgmem.c
+++ b/src/base/ftdbgmem.c
@@ -1,6 +1,7 @@
 #include <ft2build.h>
 #include FT_CONFIG_CONFIG_H
 #include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_MEMORY_H
 #include FT_SYSTEM_H
 #include FT_ERRORS_H
 #include FT_TYPES_H
@@ -173,7 +174,7 @@
       if ( new_buckets == NULL )
         return;
       
-      memset( new_buckets, 0, sizeof(FT_MemNode)*new_size );
+      MEM_Set( new_buckets, 0, sizeof(FT_MemNode)*new_size );
       
       for ( i = 0; i < table->size; i++ )
       {
@@ -211,7 +212,7 @@
     table = memory->alloc( memory, sizeof(*table) );
     if ( table == NULL ) goto Exit;
     
-    memset( table, 0, sizeof(*table) );
+    MEM_Set( table, 0, sizeof(*table) );
 
     table->size  = FT_MEM_SIZE_MIN;
     table->nodes = 0;
@@ -226,7 +227,7 @@
 
     table->buckets = memory->alloc( memory, table->size * sizeof(FT_MemNode) );
     if ( table->buckets )
-      memset( table->buckets, 0, sizeof(FT_MemNode)*table->size );
+      MEM_Set( table->buckets, 0, sizeof(FT_MemNode)*table->size );
     else
     {
       memory->free( memory, table );
@@ -408,7 +409,7 @@
         
         /* we simply invert the node's size to indicate that the node */
         /* was freed. We also change its content..                    */
-        memset( address, 0xF3, node->size );
+        MEM_Set( address, 0xF3, node->size );
 
         table->alloc_current -= node->size;
         node->size            = -node->size;
diff --git a/src/cache/ftcchunk.c b/src/cache/ftcchunk.c
index 7e60393..9fc08af 100644
--- a/src/cache/ftcchunk.c
+++ b/src/cache/ftcchunk.c
@@ -34,73 +34,62 @@
   /*************************************************************************/
   /*************************************************************************/
 
+#define  FTC_CSET_HASH(cset,start)  \
+             ((FT_UFast)(((cset)->hash << 16) | ((start) & 0xFFFF)))
 
   /* create a new chunk node, setting its cache index and ref count */
   FT_EXPORT_DEF( FT_Error )
-  FTC_ChunkNode_Init( FTC_ChunkNode  node,
-                      FTC_ChunkSet   cset,
-                      FT_UInt        index,
-                      FT_Bool        alloc )
+  ftc_chunk_node_init( FTC_ChunkNode  cnode,
+                       FTC_ChunkSet   cset,
+                       FT_UInt        gindex,
+                       FT_Bool        alloc )
   {
-    FTC_Chunk_Cache      cache = cset->cache;
-    FTC_CacheNode_Data*  data  = FTC_CACHENODE_TO_DATA_P( &node->root );
-    FT_Error             error = 0;
+    FTC_ChunkCache  ccache = cset->ccache;
+    FT_Error        error  = 0;
+    FT_UInt         len;
+    FT_UInt         start  = (gindex / cset->item_count) * cset->item_count;
 
+    cnode->cset       = cset;
+    cnode->node.hash  = FTC_CSET_HASH(cset,start);
+    cnode->item_start = start;
 
-    data->cache_index  = (FT_UShort)cache->root.cache_index;
-    data->ref_count    = (FT_Short) 0;
-    node->cset         = cset;
-    node->cset_index   = (FT_UShort)index;
-    node->num_elements = (unsigned short)(
-                          ( index + 1 < cset->num_chunks )
-                            ? cset->element_count
-                            : cset->element_max - cset->element_count*index );
+    len = cset->item_total - start;
+    if ( len > cset->item_count )
+      len = cset->item_count;
+
+    cnode->item_count = len;
+    
     if ( alloc )
     {
-      /* allocate elements array */
-      FT_Memory   memory;
-
-
-      memory = cache->root.memory;
-      error  = MEM_Alloc( node->elements,
-                          cset->element_size * cset->element_count );
+      FT_Memory  memory = ccache->cache.memory;
+     
+      error = MEM_Alloc( cnode->items, cset->item_size * cnode->item_count ); 
     }
 
+    if   (!error )
+      cset->num_chunks++;
+      
     return error;
   }
 
 
   FT_EXPORT_DEF( void )
-  FTC_ChunkNode_Destroy( FTC_ChunkNode  node )
+  ftc_chunk_node_done( FTC_ChunkNode  cnode )
   {
-    FTC_ChunkSet  cset = node->cset;
-
-
-    /* remove from parent set table */
-    cset->chunks[node->cset_index] = 0;
+    FTC_ChunkSet  cset  = cnode->cset;
+    FT_Memory     memory = cset->ccache->cache.memory;
 
     /* destroy the node */
-    cset->clazz->destroy_node( node );
+    FREE( cnode->items );
+    cnode->item_count = 0;
+    cnode->item_start = 0;
+
+    /* remove from parent set table - eventually destroy the set */
+    if ( --cset->num_chunks <= 0 )
+      FT_LruList_Remove( cset->ccache->cset_lru, (FT_LruNode) cset );
   }
 
 
-  FT_EXPORT_DEF( FT_ULong )
-  FTC_ChunkNode_Size( FTC_ChunkNode  node )
-  {
-    FTC_ChunkSet  cset = node->cset;
-
-
-    return cset->clazz->size_node( node );
-  }
-
-
-  FT_CALLBACK_TABLE_DEF
-  const FTC_CacheNode_Class  ftc_chunk_cache_node_class =
-  {
-    (FTC_CacheNode_SizeFunc)   FTC_ChunkNode_Size,
-    (FTC_CacheNode_DestroyFunc)FTC_ChunkNode_Destroy
-  };
-
 
   /*************************************************************************/
   /*************************************************************************/
@@ -112,339 +101,88 @@
 
 
   FT_EXPORT_DEF( FT_Error )
-  FTC_ChunkSet_New( FTC_Chunk_Cache  cache,
-                    FT_Pointer       type,
-                    FTC_ChunkSet    *aset )
+  ftc_chunk_set_init( FTC_ChunkSet    cset,
+                      FT_UInt         item_size,
+                      FT_UInt         item_count,
+                      FT_UInt         item_total,
+                      FTC_ChunkCache  cache )
   {
-    FT_Error      error;
-    FT_Memory     memory  = cache->root.memory;
-    FTC_Manager   manager = cache->root.manager;
-    FTC_ChunkSet  cset    = 0;
+    cset->ccache     = cache;
+    cset->num_chunks = 0;
 
-    FTC_Chunk_Cache_Class*  ccache_class;
-    FTC_ChunkSet_Class*     clazz;
+    cset->item_total = item_total;
+    cset->item_size  = item_size;
+    cset->item_count = item_count;
 
-
-    ccache_class = (FTC_Chunk_Cache_Class*)cache->root.clazz;
-    clazz        = ccache_class->cset_class;
-
-    *aset = 0;
-
-    if ( ALLOC( cset, clazz->cset_byte_size ) )
-      goto Exit;
-
-    cset->cache   = cache;
-    cset->manager = manager;
-    cset->memory  = memory;
-    cset->clazz   = clazz;
-
-    /* now compute element_max, element_count and element_size */
-    error = clazz->sizes( cset, type );
-    if ( error )
-      goto Exit;
-
-    /* compute maximum number of nodes */
-    cset->num_chunks = ( cset->element_max + cset->element_count - 1 ) /
-                       cset->element_count;
-
-    /* allocate chunk pointers table */
-    if ( ALLOC_ARRAY( cset->chunks, cset->num_chunks, FTC_ChunkNode ) )
-      goto Exit;
-
-    /* initialize set by type if needed */
-    if ( clazz->init )
-    {
-      error = clazz->init( cset, type );
-      if ( error )
-        goto Exit;
-    }
-
-    *aset = cset;
-
-  Exit:
-    if ( error && cset )
-    {
-      FREE( cset->chunks );
-      FREE( cset );
-    }
-
-    return error;
+    return 0;
   }
 
 
   FT_EXPORT_DEF( void )
-  FTC_ChunkSet_Destroy( FTC_ChunkSet  cset )
+  ftc_chunk_set_done( FTC_ChunkSet  cset )
   {
-    FTC_Chunk_Cache      cache        = cset->cache;
-    FTC_Manager          manager      = cache->root.manager;
-    FT_List              glyphs_lru   = &manager->global_lru;
-    FTC_ChunkNode*       bucket       = cset->chunks;
-    FTC_ChunkNode*       bucket_limit = bucket + cset->num_chunks;
-    FT_Memory            memory       = cache->root.memory;
-
-    FTC_ChunkSet_Class*  clazz        = cset->clazz;
+    /* nothing for now */
+    FT_UNUSED( cset );
+  }
 
 
-    /* for each bucket, free the list of glyph nodes */
-    for ( ; bucket < bucket_limit; bucket++ )
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      CHUNK CACHES                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_EXPORT_DEF( void )
+  ftc_chunk_cache_done(  FTC_ChunkCache  ccache )
+  {
+    ftc_cache_done( FTC_CACHE(ccache) );
+
+    /* simply delete all remaining glyph sets */
+    if ( ccache->cset_lru )
     {
-      FTC_ChunkNode  node = bucket[0];
-      FT_ListNode    lrunode;
-
-
-      if ( node )
-      {
-        lrunode = FTC_CHUNKNODE_TO_LRUNODE( node );
-
-        manager->num_bytes -= clazz->size_node( node );
-        manager->num_nodes--;
-
-        FT_List_Remove( glyphs_lru, lrunode );
-
-        clazz->destroy_node( node );
-
-        bucket[0] = 0;
-      }
+      FT_LruList_Destroy( ccache->cset_lru );
+      ccache->cset_lru = NULL;
     }
-
-    if ( clazz->done )
-      clazz->done( cset );
-
-    FREE( cset->chunks );
-    FREE( cset );
   }
 
 
   FT_EXPORT_DEF( FT_Error )
-  FTC_ChunkSet_Lookup_Node( FTC_ChunkSet    cset,
-                            FT_UInt         glyph_index,
-                            FTC_ChunkNode  *anode,
-                            FT_UInt        *anindex )
+  ftc_chunk_cache_init( FTC_ChunkCache    ccache,
+                        FT_LruList_Class  cset_class )
   {
-    FTC_Chunk_Cache      cache   = cset->cache;
-    FTC_Manager          manager = cache->root.manager;
-    FT_Error             error   = 0;
+    FT_Error  error;
 
-    FTC_ChunkSet_Class*  clazz   = cset->clazz;
+    error = ftc_cache_init( FTC_CACHE(ccache) );
+    if (error) goto Exit;
 
-
-    *anode = 0;
-
-    if ( glyph_index >= cset->element_max )
-      error = FTC_Err_Invalid_Argument;
-    else
-    {
-      FT_UInt         chunk_size  = cset->element_count;
-      FT_UInt         chunk_index = glyph_index / chunk_size;
-      FTC_ChunkNode*  pnode       = cset->chunks + chunk_index;
-      FTC_ChunkNode   node        = *pnode;
-
-
-      if ( !node )
-      {
-        /* we didn't found the glyph image; we will now create a new one */
-        error = clazz->new_node( cset, chunk_index, &node );
-        if ( error )
-          goto Exit;
-
-        /* store the new chunk in the cset's table */
-        *pnode = node;
-
-        /* insert the node at the start the global LRU glyph list */
-        FT_List_Insert( &manager->global_lru,
-                        FTC_CHUNKNODE_TO_LRUNODE( node ) );
-
-        manager->num_bytes += clazz->size_node( node );
-        manager->num_nodes++;
-
-        if ( manager->num_bytes > manager->max_bytes )
-        {
-          FTC_ChunkNode_Ref   ( node );
-          FTC_Manager_Compress( manager );
-          FTC_ChunkNode_Unref ( node );
-        }
-      }
-
-      *anode   = node;
-      *anindex = glyph_index - chunk_index * chunk_size;
-    }
-
+    error = FT_LruList_New( cset_class, 0, ccache,
+                            ccache->cache.memory,
+                            &ccache->cset_lru );
   Exit:
     return error;
   }
 
 
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                   CHUNK SETS LRU CALLBACKS                    *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-#define FTC_CSET_LRU_GET_CACHE( lru )   \
-          ( (FTC_Chunk_Cache)((lru)->user_data) )
-
-#define FTC_CSET_LRU_GET_MANAGER( lru ) \
-          FTC_CSET_LRU_GET_CACHE( lru )->manager
-
-#define FTC_LRUNODE_CSET( node )        \
-          ( (FTC_ChunkSet)(node)->root.data )
-
-
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_chunk_set_lru_init( FT_Lru      lru,
-                          FT_LruNode  node )
+  FT_EXPORT_DEF( FT_Error )
+  ftc_chunk_cache_lookup( FTC_ChunkCache   ccache,
+                          FTC_ChunkQuery   query,
+                          FTC_ChunkNode   *anode )
   {
-    FTC_Chunk_Cache  cache = FTC_CSET_LRU_GET_CACHE( lru );
-    FT_Error         error;
-    FTC_ChunkSet     cset;
-
-
-    error = FTC_ChunkSet_New( cache,
-                              (FT_Pointer)node->key,
-                              &cset );
+    FT_LruNode    node;
+    FT_Error      error;
+    
+    error = FT_LruList_Lookup( ccache->cset_lru, query, &node );
     if ( !error )
     {
-      /* good, now set the set index within the set object */
-      cset->cset_index = (FT_UInt)( node - lru->nodes );
-      node->root.data  = cset;
+      FTC_ChunkSet  cset = FTC_CHUNK_SET(node);
+      FT_UFast      hash = FTC_CSET_HASH( cset, query->gindex );
+
+      error = ftc_cache_lookup_node( FTC_CACHE(ccache), hash, query,
+                                     FTC_NODE_P(anode) );
     }
-
-    return error;
-  }
-
-
-  FT_CALLBACK_DEF( void )
-  ftc_chunk_set_lru_done( FT_Lru      lru,
-                          FT_LruNode  node )
-  {
-    FTC_ChunkSet  cset = FTC_LRUNODE_CSET( node );
-
-    FT_UNUSED( lru );
-
-
-    FTC_ChunkSet_Destroy( cset );
-  }
-
-
-  FT_CALLBACK_DEF( FT_Bool )
-  ftc_chunk_set_lru_compare( FT_LruNode  node,
-                             FT_LruKey   key )
-  {
-    FTC_ChunkSet  cset = FTC_LRUNODE_CSET( node );
-
-
-    return cset->clazz->compare( cset, (FT_Pointer)key );
-  }
-
-
-  FT_CALLBACK_TABLE_DEF
-  const FT_Lru_Class  ftc_chunk_set_lru_class =
-  {
-    sizeof( FT_LruRec ),
-    ftc_chunk_set_lru_init,
-    ftc_chunk_set_lru_done,
-    0,  /* no flush */
-    ftc_chunk_set_lru_compare
-  };
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                   CHUNK CACHE OBJECTS                         *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_Chunk_Cache_Init( FTC_Chunk_Cache  cache )
-  {
-    FT_Memory  memory = cache->root.memory;
-    FT_Error   error;
-
-    FTC_Chunk_Cache_Class*  ccache_clazz;
-
-
-    /* set up root node_class to be used by manager */
-    cache->root.node_clazz =
-      (FTC_CacheNode_Class*)&ftc_chunk_cache_node_class;
-
-    /* setup `compare' shortcut */
-    ccache_clazz   = (FTC_Chunk_Cache_Class*)cache->root.clazz;
-    cache->compare = ccache_clazz->cset_class->compare;
-
-    error = FT_Lru_New( &ftc_chunk_set_lru_class,
-                        FTC_MAX_CHUNK_SETS,
-                        cache,
-                        memory,
-                        1, /* pre_alloc == TRUE */
-                        &cache->csets_lru );
-    return error;
-  }
-
-
-  FT_EXPORT_DEF( void )
-  FTC_Chunk_Cache_Done( FTC_Chunk_Cache  cache )
-  {
-    /* discard glyph sets */
-    FT_Lru_Done( cache->csets_lru );
-  }
-
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_Chunk_Cache_Lookup( FTC_Chunk_Cache  cache,
-                          FT_Pointer       type,
-                          FT_UInt          gindex,
-                          FTC_ChunkNode   *anode,
-                          FT_UInt         *aindex )
-  {
-    FT_Error       error;
-    FTC_ChunkSet   cset;
-    FTC_ChunkNode  node;
-    FT_UInt        cindex;
-    FTC_Manager    manager;
-
-
-    /* check for valid `desc' delayed to FT_Lru_Lookup() */
-
-    if ( !cache || !anode || !aindex )
-      return FTC_Err_Invalid_Argument;
-
-    *anode  = 0;
-    *aindex = 0;
-    cset    = cache->last_cset;
-
-    if ( !cset || !cache->compare( cset, type ) )
-    {
-      error = FT_Lru_Lookup( cache->csets_lru,
-                             (FT_LruKey)type,
-                             (FT_Pointer*)&cset );
-      cache->last_cset = cset;
-      if ( error )
-        goto Exit;
-    }
-
-    error = FTC_ChunkSet_Lookup_Node( cset, gindex, &node, &cindex );
-    if ( error )
-      goto Exit;
-
-    /* now compress the manager's cache pool if needed */
-    manager = cache->root.manager;
-    if ( manager->num_bytes > manager->max_bytes )
-    {
-      FTC_ChunkNode_Ref   ( node );
-      FTC_Manager_Compress( manager );
-      FTC_ChunkNode_Unref ( node );
-    }
-
-    *anode  = node;
-    *aindex = cindex;
-
-  Exit:
     return error;
   }
 
diff --git a/src/cache/ftcglyph.c b/src/cache/ftcglyph.c
index c524b53..6519fd2 100644
--- a/src/cache/ftcglyph.c
+++ b/src/cache/ftcglyph.c
@@ -35,21 +35,19 @@
   /*************************************************************************/
   /*************************************************************************/
 
+#define  FTC_GSET_HASH(gset,gindex)  \
+             ((FT_UFast)(((gset)->hash << 16) | ((gindex) & 0xFFFF)))
+
 
   /* create a new glyph node, setting its cache index and ref count */
   FT_EXPORT_DEF( void )
-  FTC_GlyphNode_Init( FTC_GlyphNode  node,
-                      FTC_GlyphSet   gset,
-                      FT_UInt        gindex )
+  ftc_glyph_node_init( FTC_GlyphNode  gnode,
+                       FT_UInt        gindex,
+                       FTC_GlyphSet   gset )
   {
-    FTC_Glyph_Cache      cache = gset->cache;
-    FTC_CacheNode_Data*  data  = FTC_CACHENODE_TO_DATA_P( &node->root );
-
-
-    data->cache_index = (FT_UShort)cache->root.cache_index;
-    data->ref_count   = (FT_Short) 0;
-    node->gset_index  = (FT_UShort)gset->gset_index;
-    node->glyph_index = (FT_UShort)gindex;
+    gnode->gset      = gset;
+    gnode->node.hash = FTC_GSET_HASH( gset, gindex );
+    gset->num_glyphs++;
   }
 
 
@@ -61,71 +59,15 @@
   /* will happen!                                                 */
 
   FT_EXPORT_DEF( void )
-  FTC_GlyphNode_Destroy( FTC_GlyphNode    node,
-                         FTC_Glyph_Cache  cache )
+  ftc_glyph_node_done( FTC_GlyphNode   gnode )
   {
-    FT_LruNode    gset_lru = cache->gsets_lru->nodes + node->gset_index;
-    FTC_GlyphSet  gset     = (FTC_GlyphSet)gset_lru->root.data;
-    FT_UInt       hash     = node->glyph_index % gset->hash_size;
-
-
-    /* remove the node from its gset's bucket list */
-    {
-      FTC_GlyphNode*  pnode = gset->buckets + hash;
-      FTC_GlyphNode   cur;
-
-
-      for (;;)
-      {
-        cur = *pnode;
-        if ( !cur )
-        {
-          /* this should never happen */
-          FT_ERROR(( "FTC_GlyphNode_Destroy:"
-                     " trying to delete an unlisted node!" ));
-          return;
-        }
-
-        if ( cur == node )
-        {
-          *pnode = cur->gset_next;
-          break;
-        }
-        pnode = &cur->gset_next;
-      }
-    }
-
-    /* destroy the node */
-    gset->clazz->destroy_node( node, gset );
+    FTC_GlyphSet  gset = gnode->gset;
+    
+    if ( --gset->num_glyphs <= 0 )
+      FT_LruList_Remove( gset->gcache->gset_lru, (FT_LruNode) gset );
   }
 
 
-  /* Important: This function is called from the cache manager to */
-  /* size a given cache node during `cache compression'.  The     */
-  /* second argument is always `cache.user_data'.  Thus be        */
-  /* certain that the function FTC_Glyph_Cache_New() does indeed  */
-  /* set its `user_data' field correctly, otherwise bad things    */
-  /* will happen!                                                 */
-
-  FT_EXPORT_DEF( FT_ULong )
-  FTC_GlyphNode_Size( FTC_GlyphNode    node,
-                      FTC_Glyph_Cache  cache )
-  {
-    FT_LruNode    gset_lru = cache->gsets_lru->nodes + node->gset_index;
-    FTC_GlyphSet  gset     = (FTC_GlyphSet)gset_lru->root.data;
-
-
-    return gset->clazz->size_node( node, gset );
-  }
-
-
-  FT_CALLBACK_TABLE_DEF
-  const FTC_CacheNode_Class  ftc_glyph_cache_node_class =
-  {
-    (FTC_CacheNode_SizeFunc)   FTC_GlyphNode_Size,
-    (FTC_CacheNode_DestroyFunc)FTC_GlyphNode_Destroy
-  };
-
 
   /*************************************************************************/
   /*************************************************************************/
@@ -135,347 +77,88 @@
   /*************************************************************************/
   /*************************************************************************/
 
-
   FT_EXPORT_DEF( FT_Error )
-  FTC_GlyphSet_New( FTC_Glyph_Cache  cache,
-                    FT_Pointer       type,
-                    FTC_GlyphSet    *aset )
+  ftc_glyph_set_init( FTC_GlyphSet  gset,
+                       FT_LruList   lru )
   {
-    FT_Error                error;
-    FT_Memory               memory  = cache->root.memory;
-    FTC_Manager             manager = cache->root.manager;
-    FTC_GlyphSet            gset    = 0;
-
-    FTC_Glyph_Cache_Class*  gcache_class;
-    FTC_GlyphSet_Class*     clazz;
-
-
-    gcache_class = (FTC_Glyph_Cache_Class*)cache->root.clazz;
-    clazz        = gcache_class->gset_class;
-
-    *aset = 0;
-
-    if ( ALLOC( gset, clazz->gset_byte_size ) )
-      goto Exit;
-
-    gset->cache     = cache;
-    gset->manager   = manager;
-    gset->memory    = memory;
-    gset->hash_size = FTC_GSET_HASH_SIZE_DEFAULT;
-    gset->clazz     = clazz;
-
-    /* allocate buckets table */
-    if ( ALLOC_ARRAY( gset->buckets, gset->hash_size, FTC_GlyphNode ) )
-      goto Exit;
-
-    /* initialize gset by type if needed */
-    if ( clazz->init )
-    {
-      error = clazz->init( gset, type );
-      if ( error )
-        goto Exit;
-    }
-
-    *aset = gset;
-
-  Exit:
-    if ( error && gset )
-    {
-      FREE( gset->buckets );
-      FREE( gset );
-    }
-
-    return error;
-  }
+    FTC_GlyphCache  gcache = lru->user_data;
+    
+    gset->gcache     = gcache;
+    gset->num_glyphs = 0;
+    
+    return 0;
+  }                      
 
 
   FT_EXPORT_DEF( void )
-  FTC_GlyphSet_Destroy( FTC_GlyphSet  gset )
+  ftc_glyph_set_done( FTC_GlyphSet  gset )
   {
-    FTC_Glyph_Cache      cache        = gset->cache;
-    FTC_Manager          manager      = cache->root.manager;
-    FT_List              glyphs_lru   = &manager->global_lru;
-    FTC_GlyphNode*       bucket       = gset->buckets;
-    FTC_GlyphNode*       bucket_limit = bucket + gset->hash_size;
-    FT_Memory            memory       = cache->root.memory;
-
-    FTC_GlyphSet_Class*  clazz        = gset->clazz;
+    /* for now, nothing to be done here */
+    FT_UNUSED(gset);
+  }
 
 
-    /* for each bucket, free the list of glyph nodes */
-    for ( ; bucket < bucket_limit; bucket++ )
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      GLYPH CACHES                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_EXPORT_DEF( void )
+  ftc_glyph_cache_done(  FTC_GlyphCache  gcache )
+  {
+    /* remove all nodes in the cache */
+    ftc_cache_done( &gcache->cache );
+  
+    /* simply delete all remaining glyph sets */
+    if ( gcache->gset_lru )
     {
-      FTC_GlyphNode   node = bucket[0];
-      FTC_GlyphNode   next = 0;
-      FT_ListNode     lrunode;
-
-
-      for ( ; node; node = next )
-      {
-        next    = node->gset_next;
-        lrunode = FTC_GLYPHNODE_TO_LRUNODE( node );
-
-        manager->num_bytes -= clazz->size_node( node, gset );
-        manager->num_nodes--;
-
-        FT_List_Remove( glyphs_lru, lrunode );
-
-        clazz->destroy_node( node, gset );
-      }
-
-      bucket[0] = 0;
+      FT_LruList_Destroy( gcache->gset_lru );
+      gcache->gset_lru = NULL;
     }
-
-    if ( clazz->done )
-      clazz->done( gset );
-
-    FREE( gset->buckets );
-    FREE( gset );
   }
 
 
   FT_EXPORT_DEF( FT_Error )
-  FTC_GlyphSet_Lookup_Node( FTC_GlyphSet    gset,
-                            FT_UInt         glyph_index,
-                            FTC_GlyphNode  *anode )
+  ftc_glyph_cache_init( FTC_GlyphCache    gcache,
+                        FT_LruList_Class  gset_class )
   {
-    FTC_Glyph_Cache      cache      = gset->cache;
-    FTC_Manager          manager    = cache->root.manager;
-    FT_UInt              hash_index = glyph_index % gset->hash_size;
-    FTC_GlyphNode*       bucket     = gset->buckets + hash_index;
-    FTC_GlyphNode*       pnode      = bucket;
-    FTC_GlyphNode        node;
-    FT_Error             error;
+    FT_Error  error;
 
-    FTC_GlyphSet_Class*  clazz      = gset->clazz;
-
-
-    *anode = 0;
-
-    for ( ;; )
-    {
-      node = *pnode;
-      if ( !node )
-        break;
-
-      if ( (FT_UInt)node->glyph_index == glyph_index )
-      {
-        /* we found it! -- move glyph to start of the lists */
-        *pnode          = node->gset_next;
-        node->gset_next = bucket[0];
-        bucket[0]       = node;
-
-        FT_List_Up( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
-        *anode = node;
-        return 0;
-      }
-      /* go to next node in bucket */
-      pnode = &node->gset_next;
-    }
-
-    /* we didn't found the glyph image, we will now create a new one */
-    error = clazz->new_node( gset, glyph_index, &node );
-    if ( error )
-      goto Exit;
-
-    /* insert the node at the start of our bucket list */
-    node->gset_next = bucket[0];
-    bucket[0]       = node;
-
-    /* insert the node at the start the global LRU glyph list */
-    FT_List_Insert( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
-
-    manager->num_bytes += clazz->size_node( node, gset );
-    manager->num_nodes++;
-
-    if ( manager->num_bytes > manager->max_bytes )
-    {
-      FTC_GlyphNode_Ref   ( node );
-      FTC_Manager_Compress( manager );
-      FTC_GlyphNode_Unref ( node );
-    }
-
-    *anode = node;
-
+    error = ftc_cache_init( FTC_CACHE(gcache) );
+    if (error) goto Exit;
+        
+    error = FT_LruList_New( gset_class, 0, gcache,
+                            gcache->cache.memory,
+                            &gcache->gset_lru );
   Exit:
     return error;
   }
 
 
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                   GLYPH SETS LRU CALLBACKS                    *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-#define FTC_GSET_LRU_GET_CACHE( lru )   \
-          ( (FTC_Glyph_Cache)(lru)->user_data )
-
-#define FTC_GSET_LRU_GET_MANAGER( lru ) \
-          FTC_GSET_LRU_GET_CACHE( lru )->manager
-
-#define FTC_LRUNODE_GSET( node )        \
-          ( (FTC_GlyphSet)(node)->root.data )
-
-
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_glyph_set_lru_init( FT_Lru      lru,
-                          FT_LruNode  node )
+  FT_EXPORT_DEF( FT_Error )
+  ftc_glyph_cache_lookup( FTC_GlyphCache  gcache,
+                          FTC_GlyphQuery  query,
+                          FTC_GlyphNode  *anode )
   {
-    FTC_Glyph_Cache  cache = FTC_GSET_LRU_GET_CACHE( lru );
-    FT_Error         error;
-    FTC_GlyphSet     gset;
-
-
-    error = FTC_GlyphSet_New( cache, (FT_Pointer)node->key, &gset );
+    FT_LruNode    node;
+    FT_Error      error;
+    
+    error = FT_LruList_Lookup( gcache->gset_lru, query, &node );
     if ( !error )
     {
-      /* good, now set the gset index within the gset object */
-      gset->gset_index = (FT_UInt)( node - lru->nodes );
-      node->root.data  = gset;
+      FTC_GlyphSet  gset = (FTC_GlyphSet) node;
+      FT_UFast      hash = FTC_GSET_HASH( gset, query->gindex );
+      
+      error = ftc_cache_lookup_node( FTC_CACHE(gcache), hash, query,
+                                     FTC_NODE_P(anode) );
     }
-
     return error;
   }
 
 
-  FT_CALLBACK_DEF( void )
-  ftc_glyph_set_lru_done( FT_Lru      lru,
-                          FT_LruNode  node )
-  {
-    FTC_GlyphSet  gset = FTC_LRUNODE_GSET( node );
-
-    FT_UNUSED( lru );
-
-
-    FTC_GlyphSet_Destroy( gset );
-  }
-
-
-  FT_CALLBACK_DEF( FT_Bool )
-  ftc_glyph_set_lru_compare( FT_LruNode  node,
-                             FT_LruKey   key )
-  {
-    FTC_GlyphSet  gset = FTC_LRUNODE_GSET( node );
-
-
-    return gset->clazz->compare( gset, (FT_Pointer)key );
-  }
-
-
-  FT_CALLBACK_TABLE_DEF
-  const FT_Lru_Class  ftc_glyph_set_lru_class =
-  {
-    sizeof( FT_LruRec ),
-    ftc_glyph_set_lru_init,
-    ftc_glyph_set_lru_done,
-    0,  /* no flush */
-    ftc_glyph_set_lru_compare
-  };
-
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*****                                                               *****/
-  /*****                      GLYPH CACHE OBJECTS                      *****/
-  /*****                                                               *****/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_Glyph_Cache_Init( FTC_Glyph_Cache  cache )
-  {
-    FT_Memory  memory = cache->root.memory;
-    FT_Error   error;
-
-    FTC_Glyph_Cache_Class*  gcache_clazz;
-
-
-    /* set up root node_class to be used by manager */
-    cache->root.node_clazz =
-      (FTC_CacheNode_Class*)&ftc_glyph_cache_node_class;
-
-    /* setup the `compare' shortcut */
-    gcache_clazz   = (FTC_Glyph_Cache_Class*)cache->root.clazz;
-    cache->compare = gcache_clazz->gset_class->compare;
-
-    /* The following is extremely important for ftc_destroy_glyph_image() */
-    /* to work properly, as the second parameter that is sent to it       */
-    /* through the cache manager is `cache_data' and must be set to       */
-    /* `cache' here.                                                      */
-    /*                                                                    */
-    cache->root.cache_data = cache;
-
-    error = FT_Lru_New( &ftc_glyph_set_lru_class,
-                        FTC_MAX_GLYPH_SETS,
-                        cache,
-                        memory,
-                        1, /* pre_alloc == TRUE */
-                        &cache->gsets_lru );
-    return error;
-  }
-
-
-  FT_EXPORT_DEF( void )
-  FTC_Glyph_Cache_Done( FTC_Glyph_Cache  cache )
-  {
-    /* discard glyph sets */
-    FT_Lru_Done( cache->gsets_lru );
-  }
-
-
-  FT_EXPORT_DEF( FT_Error )
-  FTC_Glyph_Cache_Lookup( FTC_Glyph_Cache  cache,
-                          FT_Pointer       type,
-                          FT_UInt          gindex,
-                          FTC_GlyphNode   *anode )
-  {
-    FT_Error       error;
-    FTC_GlyphSet   gset;
-    FTC_GlyphNode  node;
-    FTC_Manager    manager;
-
-
-    /* check for valid `desc' delayed to FT_Lru_Lookup() */
-
-    if ( !cache || !anode )
-      return FTC_Err_Invalid_Argument;
-
-    *anode = 0;
-    gset   = cache->last_gset;
-
-    if ( !gset || !cache->compare( gset, type ) )
-    {
-      error = FT_Lru_Lookup( cache->gsets_lru,
-                             (FT_LruKey)type,
-                             (FT_Pointer*)&gset );
-      cache->last_gset = gset;
-      if ( error )
-        goto Exit;
-    }
-
-    error = FTC_GlyphSet_Lookup_Node( gset, gindex, &node );
-    if ( error )
-      goto Exit;
-
-    /* now compress the manager's cache pool if needed */
-    manager = cache->root.manager;
-    if ( manager->num_bytes > manager->max_bytes )
-    {
-      FTC_GlyphNode_Ref   ( node );
-      FTC_Manager_Compress( manager );
-      FTC_GlyphNode_Unref ( node );
-    }
-
-    *anode = node;
-
-  Exit:
-    return error;
-  }
-
 
 /* END */
diff --git a/src/cache/ftcimage.c b/src/cache/ftcimage.c
index 2c93a23..c635ae9 100644
--- a/src/cache/ftcimage.c
+++ b/src/cache/ftcimage.c
@@ -19,6 +19,7 @@
 #include <ft2build.h>
 #include FT_CACHE_H
 #include FT_CACHE_IMAGE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
 #include FT_INTERNAL_MEMORY_H
 
 #include "ftcerror.h"
@@ -27,30 +28,36 @@
 #include <stdlib.h>     /* labs()   */
 
 
-  /* the FT_Glyph image `glyph node' type */
-  typedef struct  FTC_GlyphImageRec_
+  /* the FT_Glyph image node type */
+  typedef struct  FTC_ImageNodeRec_
   {
-    FTC_GlyphNodeRec  root;
-    FT_Glyph          ft_glyph;
+    FTC_GlyphNodeRec  gnode;
+    FT_Glyph          glyph;
 
-  } FTC_GlyphImageRec, *FTC_GlyphImage;
+  } FTC_ImageNodeRec, *FTC_ImageNode;
 
+#define  FTC_IMAGE_NODE(x)         ((FTC_ImageNode)(x))
+#define  FTC_IMAGE_NODE_GINDEX(x)  FTC_GLYPH_NODE_GINDEX(x)
 
-  /* the glyph image queue type */
+  /* the glyph image set type */
   typedef struct  FTC_ImageSetRec_
   {
-    FTC_GlyphSetRec  root;
+    FTC_GlyphSetRec  gset;
     FTC_Image_Desc   description;
 
   } FTC_ImageSetRec, *FTC_ImageSet;
 
+#define  FTC_IMAGE_SET(x)  ((FTC_ImageSet)(x))
 
-  typedef struct  FTC_Image_CacheRec_
+#define  FTC_IMAGE_SET_MEMORY(x)  FTC_GLYPH_SET_MEMORY(&(x)->gset)
+
+
+  typedef struct FTC_ImageQueryRec_
   {
-    FTC_Glyph_CacheRec  root;
-
-  } FTC_Image_CacheRec;
-
+    FTC_GlyphQueryRec  glyph;
+    FTC_Image_Desc     desc;
+  
+  } FTC_ImageQueryRec, *FTC_ImageQuery;
 
 
   /*************************************************************************/
@@ -62,47 +69,41 @@
   /*************************************************************************/
 
 
+ /* finalize a given glyph image node */
   FT_CALLBACK_DEF( void )
-  ftc_glyph_image_node_destroy( FTC_GlyphImage  node,
-                                FTC_GlyphSet    gset )
+  ftc_image_node_done( FTC_ImageNode  inode )
   {
-    FT_Memory  memory = gset->memory;
-
-
-    FT_Done_Glyph( node->ft_glyph );
-    FREE( node );
+    if (inode->glyph)
+    {
+      FT_Done_Glyph( inode->glyph );
+      inode->glyph = NULL;
+    }
   }
 
 
+ /* initialize a new glyph image node */
   FT_CALLBACK_DEF( FT_Error )
-  ftc_glyph_image_node_new( FTC_GlyphSet     gset,
-                            FT_UInt          glyph_index,
-                            FTC_GlyphImage  *anode )
+  ftc_image_node_init( FTC_ImageNode   inode,
+                       FTC_GlyphQuery  query )
   {
-    FT_Memory       memory   = gset->memory;
-    FTC_ImageSet    imageset = (FTC_ImageSet)gset;
+    FTC_ImageSet    iset   = FTC_IMAGE_SET( query->gset );
+    FT_Memory       memory = FTC_IMAGE_SET_MEMORY( iset );
     FT_Error        error;
-    FTC_GlyphImage  node = 0;
     FT_Face         face;
     FT_Size         size;
 
-
-    /* allocate node */
-    if ( ALLOC( node, sizeof ( *node ) ) )
-      goto Exit;
-
     /* initialize its inner fields */
-    FTC_GlyphNode_Init( FTC_GLYPHNODE( node ), gset, glyph_index );
+    ftc_glyph_node_init( FTC_GLYPH_NODE(inode), query->gindex, query->gset );
 
     /* we will now load the glyph image */
-    error = FTC_Manager_Lookup_Size( gset->manager,
-                                     &imageset->description.font,
+    error = FTC_Manager_Lookup_Size( iset->gset.gcache->cache.manager,
+                                     &iset->description.font,
                                      &face, &size );
     if ( !error )
     {
-      FT_UInt  gindex = node->root.glyph_index;
+      FT_UInt  gindex      = FTC_GLYPH_NODE_GINDEX(inode);
       FT_UInt  load_flags  = FT_LOAD_DEFAULT;
-      FT_UInt  image_type  = imageset->description.image_type;
+      FT_UInt  image_type  = iset->description.image_type;
 
 
       if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
@@ -142,31 +143,29 @@
 
           error = FT_Get_Glyph( face->glyph, &glyph );
           if ( !error )
-            node->ft_glyph = glyph;
+          {
+            inode->glyph = glyph;
+            goto Exit;
+          }
         }
         else
           error = FTC_Err_Invalid_Argument;
       }
     }
+    
+    /* in case of error */
+    ftc_glyph_node_done( FTC_GLYPH_NODE(inode) );
 
   Exit:
-    if ( error && node )
-      FREE( node );
-
-    *anode = node;
     return error;
   }
 
 
-  /* this function is important because it is both part of */
-  /* an FTC_GlyphSet_Class and an FTC_CacheNode_Class      */
-  /*                                                       */
   FT_CALLBACK_DEF( FT_ULong )
-  ftc_glyph_image_node_size( FTC_GlyphImage  node )
+  ftc_image_node_weight( FTC_ImageNode  inode )
   {
     FT_ULong  size  = 0;
-    FT_Glyph  glyph = node->ft_glyph;
-
+    FT_Glyph  glyph = inode->glyph;
 
     switch ( glyph->format )
     {
@@ -198,11 +197,27 @@
       ;
     }
 
-    size += sizeof ( *node );
+    size += sizeof ( *inode );
     return size;
   }
 
 
+ /* this function assumes that the desired node's glyph set has been */
+ /* set by a previous call to ftc_image_set_compare..                */
+ /*                                                                  */
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_image_node_compare( FTC_ImageNode   inode,
+                          FTC_ImageQuery  iquery )
+  {
+    FTC_ImageSet  iset = FTC_IMAGE_SET(inode->gnode.gset);
+
+   /* only if same glyph index and image set description */
+    return FT_BOOL( iquery->glyph.gindex == FTC_IMAGE_NODE_GINDEX(inode) &&
+                    iquery->glyph.gset   == inode->gnode.gset );
+  }
+
+
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -214,33 +229,47 @@
 
   FT_CALLBACK_DEF( FT_Error )
   ftc_image_set_init( FTC_ImageSet     iset,
-                      FTC_Image_Desc*  type )
+                      FTC_ImageQuery   query,
+                      FT_LruList       lru )
   {
-    iset->description = *type;
+    ftc_glyph_set_init( &iset->gset, lru );
+    iset->description = query->desc;
+    
+    /* now compute hash from description - this is _very_ important */
+    iset->gset.hash   = FTC_IMAGE_DESC_HASH(&query->desc);
+    query->glyph.gset = FTC_GLYPH_SET(iset);
+
     return 0;
   }
 
 
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_image_set_compare( FTC_ImageSet     iset,
-                         FTC_Image_Desc*  type )
+  ftc_image_set_compare( FTC_ImageSet    iset,
+                         FTC_ImageQuery  iquery )
   {
-    return FT_BOOL( !memcmp( &iset->description, type, sizeof ( *type ) ) );
+    FT_Bool  result;
+
+    /* we must set iquery.glyph.gset for faster glyph node comparisons */
+    result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &iset->description, &iquery->desc ) );
+    if ( result )
+      iquery->glyph.gset = &iset->gset;
+    
+    return result;
   }
 
 
   FT_CALLBACK_TABLE_DEF
-  const FTC_GlyphSet_Class  ftc_glyph_image_set_class =
+  const FT_LruList_ClassRec  ftc_image_set_class =
   {
+    sizeof( FT_LruListRec ),
+    (FT_LruList_InitFunc) NULL,
+    (FT_LruList_DoneFunc) NULL,
+    
     sizeof( FTC_ImageSetRec ),
-
-    (FTC_GlyphSet_InitFunc)       ftc_image_set_init,
-    (FTC_GlyphSet_DoneFunc)       0,
-    (FTC_GlyphSet_CompareFunc)    ftc_image_set_compare,
-
-    (FTC_GlyphSet_NewNodeFunc)    ftc_glyph_image_node_new,
-    (FTC_GlyphSet_SizeNodeFunc)   ftc_glyph_image_node_size,
-    (FTC_GlyphSet_DestroyNodeFunc)ftc_glyph_image_node_destroy
+    (FT_LruNode_InitFunc)    ftc_image_set_init,
+    (FT_LruNode_DoneFunc)    ftc_glyph_set_init,
+    (FT_LruNode_FlushFunc)   NULL,
+    (FT_LruNode_CompareFunc) ftc_image_set_compare
   };
 
 
@@ -253,15 +282,25 @@
   /*************************************************************************/
 
 
-  FT_CALLBACK_TABLE_DEF
-  const FTC_Glyph_Cache_Class  ftc_glyph_image_cache_class =
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_image_cache_init( FTC_Image_Cache  cache )
   {
-    {
-      sizeof( FTC_Image_CacheRec ),
-      (FTC_Cache_InitFunc) FTC_Glyph_Cache_Init,
-      (FTC_Cache_DoneFunc) FTC_Glyph_Cache_Done
-    },
-    (FTC_GlyphSet_Class*) &ftc_glyph_image_set_class
+    return ftc_glyph_cache_init( (FTC_GlyphCache) cache, &ftc_image_set_class );
+  }
+  
+
+  FT_CALLBACK_TABLE_DEF
+  const FTC_Cache_ClassRec  ftc_image_cache_class =
+  {
+    sizeof( FTC_GlyphCacheRec ),
+    (FTC_Cache_InitFunc)    ftc_image_cache_init,
+    (FTC_Cache_DoneFunc)    ftc_glyph_cache_done,
+    
+    sizeof( FTC_ImageNodeRec ),
+    (FTC_Node_InitFunc)     ftc_image_node_init,
+    (FTC_Node_WeightFunc)   ftc_image_node_weight,
+    (FTC_Node_CompareFunc)  ftc_image_node_compare,
+    (FTC_Node_DoneFunc)     ftc_image_node_done
   };
 
 
@@ -273,36 +312,73 @@
   {
     return FTC_Manager_Register_Cache(
              manager,
-             (FTC_Cache_Class*)&ftc_glyph_image_cache_class,
-             (FTC_Cache*)acache );
+             (FTC_Cache_Class) &ftc_image_cache_class,
+             FTC_CACHE_P(acache) );
   }
 
 
   /* documentation is in ftcimage.h */
 
   FT_EXPORT_DEF( FT_Error )
-  FTC_Image_Cache_Lookup( FTC_Image_Cache  cache,
+  FTC_Image_Cache_Acquire( FTC_Image_Cache  cache,
+                           FTC_Image_Desc*  desc,
+                           FT_UInt          gindex,
+                           FT_Glyph        *aglyph,
+                           FTC_Node        *anode )
+  {
+    FTC_ImageQueryRec  query;
+    FTC_ImageNode      node;
+    FT_Error           error;
+    
+    /* some argument checks are delayed to ftc_glyph_cache_lookup */
+    if ( !cache || !desc || !aglyph )
+      return FTC_Err_Invalid_Argument;
+
+    *aglyph = NULL;
+    
+    if ( anode )
+      *anode  = NULL;
+
+    query.glyph.gindex = gindex;
+    query.glyph.gset   = NULL;
+    query.desc         = *desc;
+    error = ftc_glyph_cache_lookup( FTC_GLYPH_CACHE(cache),
+                                    &query.glyph,
+                                    (FTC_GlyphNode*) &node );
+    if (!error)
+    {
+      *aglyph = node->glyph;
+      
+      if (anode)
+      {
+        *anode = (FTC_Node) node;
+        FTC_NODE(node)->ref_count++;
+      }
+    }
+
+    return error;
+  }                           
+
+
+  FT_EXPORT_DEF( void )
+  FTC_Image_Cache_Release( FTC_Image_Cache  icache,
+                           FTC_Node         node )
+  {
+    ftc_node_unref( node, FTC_CACHE(icache) );
+  }
+
+
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Image_Cache_Lookup( FTC_Image_Cache  icache,
                           FTC_Image_Desc*  desc,
                           FT_UInt          gindex,
                           FT_Glyph        *aglyph )
   {
-    FT_Error       error;
-    FTC_GlyphNode  node;
-
-
-    /* some argument checks are delayed to FTC_Glyph_Cache_Lookup */
-
-    if ( !aglyph )
-      return FTC_Err_Invalid_Argument;
-
-    error = FTC_Glyph_Cache_Lookup( (FTC_Glyph_Cache)cache,
-                                    desc, gindex, &node );
-
-    if ( !error )
-      *aglyph = ((FTC_GlyphImage)node)->ft_glyph;
-
-    return error;
+    return FTC_Image_Cache_Acquire( icache, desc, gindex, aglyph, NULL );
   }
 
 
+
 /* END */
diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c
index 7076305..08fe202 100644
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -19,6 +19,7 @@
 #include <ft2build.h>
 #include FT_CACHE_H
 #include FT_CACHE_MANAGER_H
+#include FT_CACHE_INTERNAL_LRU_H
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_LIST_H
@@ -30,187 +31,225 @@
 #undef  FT_COMPONENT
 #define FT_COMPONENT  trace_cache
 
-#define FTC_LRU_GET_MANAGER( lru )  (FTC_Manager)lru->user_data
+#define FTC_LRU_GET_MANAGER( lru )  ((FTC_Manager)(lru)->user_data)
 
 
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
-  /*****               FACE & SIZE LRU CALLBACKS                       *****/
+  /*****                    FACE LRU IMPLEMENTATION                    *****/
   /*****                                                               *****/
   /*************************************************************************/
   /*************************************************************************/
 
+  typedef struct FTC_FaceNodeRec_*   FTC_FaceNode;
+
+  typedef struct FTC_SizeNodeRec_*   FTC_SizeNode;
+
+  typedef struct FTC_FaceNodeRec_
+  {
+    FT_LruNodeRec  lru;
+    FT_Face        face;
+
+  } FTC_FaceNodeRec;
+
+
+  typedef struct FTC_SizeNodeRec_
+  {
+    FT_LruNodeRec  lru;
+    FT_Size        size;
+
+  } FTC_SizeNodeRec;
+
+
 
   FT_CALLBACK_DEF( FT_Error )
-  ftc_manager_init_face( FT_Lru      lru,
-                         FT_LruNode  node )
+  ftc_face_node_init( FTC_FaceNode node,
+                      FTC_FaceID   face_id,
+                      FT_LruList   list )
   {
-    FTC_Manager  manager = FTC_LRU_GET_MANAGER( lru );
+    FTC_Manager  manager = FTC_LRU_GET_MANAGER(list);
     FT_Error     error;
-    FT_Face      face;
 
 
-    error = manager->request_face( (FTC_FaceID)node->key,
+    error = manager->request_face( face_id,
                                    manager->library,
                                    manager->request_data,
-                                   (FT_Face*)&node->root.data );
+                                   &node->face );
     if ( !error )
     {
       /* destroy initial size object; it will be re-created later */
-      face = (FT_Face)node->root.data;
-      if ( face->size )
-        FT_Done_Size( face->size );
+      if ( node->face->size )
+        FT_Done_Size( node->face->size );
     }
 
     return error;
   }
 
 
-  /* helper function for ftc_manager_done_face() */
-  FT_CALLBACK_DEF( FT_Bool )
-  ftc_manager_size_selector( FT_Lru      lru,
-                             FT_LruNode  node,
-                             FT_Pointer  data )
-  {
-    FT_UNUSED( lru );
-
-    return FT_BOOL( ((FT_Size)node->root.data)->face == (FT_Face)data );
-  }
+      /* helper function for ftc_manager_done_face() */
+      FT_CALLBACK_DEF( FT_Bool )
+      ftc_size_node_select( FTC_SizeNode  node,
+                            FT_Face       face )
+      {
+        return FT_BOOL( node->size->face == face );
+      }
 
 
   FT_CALLBACK_DEF( void )
-  ftc_manager_done_face( FT_Lru      lru,
-                         FT_LruNode  node )
+  ftc_face_node_done( FTC_FaceNode  node,
+                      FT_LruList    list )
   {
-    FTC_Manager  manager = FTC_LRU_GET_MANAGER( lru );
-    FT_Face      face    = (FT_Face)node->root.data;
+    FTC_Manager  manager = FTC_LRU_GET_MANAGER(list);
+    FT_Face      face    = node->face;
 
 
     /* 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 );
+    FT_LruList_Remove_Selection( manager->sizes_list,
+                                 (FT_LruNode_SelectFunc) ftc_size_node_select,
+                                 face );
 
     /* all right, we can discard the face now */
     FT_Done_Face( face );
-    node->root.data = 0;
+    node->face = NULL;
   }
 
 
-  typedef struct  FTC_FontRequest_
+  FT_CALLBACK_TABLE_DEF
+  const FT_LruList_ClassRec   ftc_face_list_class =
   {
-    FT_Face    face;
-    FT_UShort  width;
-    FT_UShort  height;
+    sizeof( FT_LruListRec ),
+    (FT_LruList_InitFunc) 0,
+    (FT_LruList_DoneFunc) 0,
 
-  } FTC_FontRequest;
+    sizeof( FTC_FaceNodeRec ),
+    (FT_LruNode_InitFunc)    ftc_face_node_init,
+    (FT_LruNode_DoneFunc)    ftc_face_node_done,
+    (FT_LruNode_FlushFunc)   0,  /* no flushing needed..                    */
+    (FT_LruNode_CompareFunc) 0,  /* direct comparison of FTC_FaceID handles */
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      SIZES LRU IMPLEMENTATION                 *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  typedef struct  FTC_SizeQueryRec_
+  {
+    FT_Face  face;
+    FT_UInt  width;
+    FT_UInt  height;
+
+  } FTC_SizeQueryRec, *FTC_SizeQuery;
+
 
 
   FT_CALLBACK_DEF( FT_Error )
-  ftc_manager_init_size( FT_Lru      lru,
-                         FT_LruNode  node )
+  ftc_size_node_init( FTC_SizeNode   node,
+                      FTC_SizeQuery  query )
   {
-    FTC_FontRequest*  font_req = (FTC_FontRequest*)node->key;
-    FT_Size           size;
-    FT_Error          error;
-    FT_Face           face = font_req->face;
-
-    FT_UNUSED( lru );
+    FT_Face   face = query->face;
+    FT_Size   size;
+    FT_Error  error;
 
 
-    node->root.data = 0;
+    node->size = NULL;
     error = FT_New_Size( face, &size );
     if ( !error )
     {
       FT_Activate_Size( size );
-      error = FT_Set_Pixel_Sizes( face,
-                                  font_req->width,
-                                  font_req->height );
+      error = FT_Set_Pixel_Sizes( query->face,
+                                  query->width,
+                                  query->height );
       if ( error )
         FT_Done_Size( size );
       else
-        node->root.data = size;
+        node->size = size;
     }
     return error;
   }
 
 
   FT_CALLBACK_DEF( void )
-  ftc_manager_done_size( FT_Lru      lru,
-                         FT_LruNode  node )
+  ftc_size_node_done( FTC_SizeNode  node )
   {
-    FT_UNUSED( lru );
-
-    FT_Done_Size( (FT_Size)node->root.data );
-    node->root.data = 0;
+    if (node->size)
+    {
+      FT_Done_Size( node->size );
+      node->size = NULL;
+    }
   }
 
 
   FT_CALLBACK_DEF( FT_Error )
-  ftc_manager_flush_size( FT_Lru      lru,
-                          FT_LruNode  node,
-                          FT_LruKey   key )
+  ftc_size_node_flush( FTC_SizeNode   node,
+                       FTC_SizeQuery  query )
   {
-    FTC_FontRequest*  req  = (FTC_FontRequest*)key;
-    FT_Size           size = (FT_Size)node->root.data;
-    FT_Error          error;
+    FT_Size   size = node->size;
+    FT_Error  error;
 
 
-    if ( size->face == req->face )
+    if ( size->face == query->face )
     {
       FT_Activate_Size( size );
-      error = FT_Set_Pixel_Sizes( req->face, req->width, req->height );
+      error = FT_Set_Pixel_Sizes( query->face, query->width, query->height );
       if ( error )
+      {
         FT_Done_Size( size );
+        node->size = NULL;
+      }
     }
     else
     {
       FT_Done_Size( size );
-      node->key = key;
-      error = ftc_manager_init_size( lru, node );
+      node->size = NULL;
+
+      error = ftc_size_node_init( node, query );
     }
     return error;
   }
 
 
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_manager_compare_size( FT_LruNode  node,
-                            FT_LruKey   key )
+  ftc_size_node_compare( FTC_SizeNode   node,
+                         FTC_SizeQuery  query )
   {
-    FTC_FontRequest*  req  = (FTC_FontRequest*)key;
-    FT_Size           size = (FT_Size)node->root.data;
+    FT_Size  size = node->size;
 
-    FT_UNUSED( node );
-
-
-    return FT_BOOL( size->face           == req->face   &&
-                    size->metrics.x_ppem == req->width  &&
-                    size->metrics.y_ppem == req->height );
+    return FT_BOOL( size->face           == query->face   &&
+                    (FT_UInt) size->metrics.x_ppem == query->width  &&
+                    (FT_UInt) size->metrics.y_ppem == query->height );
   }
 
 
   FT_CALLBACK_TABLE_DEF
-  const FT_Lru_Class  ftc_face_lru_class =
+  const FT_LruList_ClassRec  ftc_size_list_class =
   {
-    sizeof ( FT_LruRec ),
-    ftc_manager_init_face,
-    ftc_manager_done_face,
-    0,
-    0
+    sizeof ( FT_LruListRec ),
+    (FT_LruList_InitFunc)  0,
+    (FT_LruList_DoneFunc)  0,
+
+    sizeof( FTC_SizeNodeRec ),
+    (FT_LruNode_InitFunc)     ftc_size_node_init,
+    (FT_LruNode_DoneFunc)     ftc_size_node_done,
+    (FT_LruNode_FlushFunc)    ftc_size_node_flush,
+    (FT_LruNode_CompareFunc)  ftc_size_node_compare
   };
 
 
-  FT_CALLBACK_TABLE_DEF
-  const FT_Lru_Class  ftc_size_lru_class =
-  {
-    sizeof ( FT_LruRec ),
-    ftc_manager_init_size,
-    ftc_manager_done_size,
-    ftc_manager_flush_size,
-    ftc_manager_compare_size
-  };
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    CACHE MANAGER ROUTINES                     *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
 
 
   /* documentation is in ftcache.h */
@@ -246,26 +285,25 @@
     if ( max_bytes == 0 )
       max_bytes = FTC_MAX_BYTES_DEFAULT;
 
-    error = FT_Lru_New( &ftc_face_lru_class,
-                        max_faces,
-                        manager,
-                        memory,
-                        1, /* pre_alloc = TRUE */
-                        (FT_Lru*)&manager->faces_lru );
+    error = FT_LruList_New( &ftc_face_list_class,
+                            max_faces,
+                            manager,
+                            memory,
+                            &manager->faces_list );
     if ( error )
       goto Exit;
 
-    error = FT_Lru_New( &ftc_size_lru_class,
-                        max_sizes,
-                        manager,
-                        memory,
-                        1, /* pre_alloc = TRUE */
-                        (FT_Lru*)&manager->sizes_lru );
+    error = FT_LruList_New( &ftc_size_list_class,
+                            max_sizes,
+                            manager,
+                            memory,
+                            &manager->sizes_list );
     if ( error )
       goto Exit;
 
     manager->library      = library;
-    manager->max_bytes    = max_bytes;
+    manager->max_weight   = max_bytes;
+    manager->cur_weight   = 0;
     manager->request_face = requester;
     manager->request_data = req_data;
 
@@ -274,8 +312,8 @@
   Exit:
     if ( error && manager )
     {
-      FT_Lru_Done( manager->faces_lru );
-      FT_Lru_Done( manager->sizes_lru );
+      FT_LruList_Destroy( manager->faces_list );
+      FT_LruList_Destroy( manager->sizes_list );
       FREE( manager );
     }
 
@@ -305,18 +343,18 @@
 
       if ( cache )
       {
-        cache->clazz->done_cache( cache );
+        cache->clazz->cache_done( cache );
         FREE( cache );
         manager->caches[index] = 0;
       }
     }
 
     /* discard faces and sizes */
-    FT_Lru_Done( manager->faces_lru );
-    manager->faces_lru = 0;
+    FT_LruList_Destroy( manager->faces_list );
+    manager->faces_list = 0;
 
-    FT_Lru_Done( manager->sizes_lru );
-    manager->sizes_lru = 0;
+    FT_LruList_Destroy( manager->sizes_list );
+    manager->sizes_list = 0;
 
     FREE( manager );
   }
@@ -329,8 +367,8 @@
   {
     if (manager )
     {
-      FT_Lru_Reset( manager->sizes_lru );
-      FT_Lru_Reset( manager->faces_lru );
+      FT_LruList_Reset( manager->sizes_list );
+      FT_LruList_Reset( manager->faces_list );
     }
     /* XXX: FIXME: flush the caches? */
   }
@@ -343,12 +381,24 @@
                            FTC_FaceID   face_id,
                            FT_Face     *aface )
   {
+    FT_Error      error;
+    FTC_FaceNode  node;
+
+    if ( aface == NULL )
+      return FTC_Err_Bad_Argument;
+
+    *aface = NULL;
+
     if ( !manager )
       return FTC_Err_Invalid_Cache_Handle;
 
-    return  FT_Lru_Lookup( manager->faces_lru,
-                           (FT_LruKey)face_id,
-                           (FT_Pointer*)aface );
+    error  = FT_LruList_Lookup( manager->faces_list,
+                                (FT_LruKey) face_id,
+                                (FT_LruNode*) &node );
+    if (!error)
+      *aface = node->face;
+    
+    return error;
   }
 
 
@@ -360,12 +410,10 @@
                            FT_Face     *aface,
                            FT_Size     *asize )
   {
-    FTC_FontRequest  req;
-    FT_Error         error;
+    FT_Error  error;
 
 
     /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
-
     if ( aface )
       *aface = 0;
 
@@ -375,23 +423,24 @@
     error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
     if ( !error )
     {
-      FT_Size  size;
+      FTC_SizeQueryRec  query;
+      FTC_SizeNode      node;
 
 
-      req.face   = *aface;
-      req.width  = font->pix_width;
-      req.height = font->pix_height;
+      query.face   = *aface;
+      query.width  = font->pix_width;
+      query.height = font->pix_height;
 
-      error = FT_Lru_Lookup( manager->sizes_lru,
-                             (FT_LruKey)&req,
-                             (FT_Pointer*)&size );
+      error = FT_LruList_Lookup( manager->sizes_list,
+                                 (FT_LruKey) &query,
+                                 (FT_LruNode*) &node );
       if ( !error )
       {
         /* select the size as the current one for this face */
-        (*aface)->size = size;
+        FT_Activate_Size( node->size );
 
         if ( asize )
-          *asize = size;
+          *asize = node->size;
       }
     }
 
@@ -399,6 +448,219 @@
   }
 
 
+
+ /* add a new node to the head of the manager's circular MRU list */
+  static void
+  ftc_node_mru_link( FTC_Node     node,
+                     FTC_Manager  manager )
+  {
+    FTC_Node  first = manager->nodes_list;
+
+    if (first)
+    {
+      node->mru_prev  = first->mru_prev;
+      node->mru_next  = first;
+
+      first->mru_prev->mru_next = node;
+      first->mru_prev           = node;
+    }
+    else
+    {
+      node->mru_next = node;
+      node->mru_prev = node;
+    }
+    manager->nodes_list = node;
+    manager->num_nodes++;
+  }
+
+
+ /* remove a node from the manager's MRU list */
+  static void
+  ftc_node_mru_unlink( FTC_Node     node,
+                       FTC_Manager  manager )
+  {
+    FTC_Node  prev  = node->mru_prev;
+    FTC_Node  next  = node->mru_next;
+    FTC_Node  first = manager->nodes_list;
+
+    prev->mru_next = next;
+    next->mru_prev = prev;
+
+    if ( node->mru_next == first )
+    {
+      /* this is the last node in the list, update its head pointer */
+      if ( node == first )
+        manager->nodes_list = NULL;
+      else
+        first->mru_prev = prev;
+    }
+
+    node->mru_next = NULL;
+    node->mru_prev = NULL;
+    manager->num_nodes--;
+  }
+
+
+ /* move a node to the head of the manager's MRU list */
+  static void
+  ftc_node_mru_up( FTC_Node     node,
+                   FTC_Manager  manager )
+  {
+    FTC_Node  first = manager->nodes_list;
+
+    if ( node != first )
+    {
+      ftc_node_mru_unlink( node, manager );
+      ftc_node_mru_link( node, manager );
+    }
+  }
+
+
+ /* remove a node from its cache's hash table */
+  static void
+  ftc_node_hash_unlink( FTC_Node   node,
+                        FTC_Cache  cache )
+  {
+    FTC_Node  *pnode = cache->buckets + (node->hash % cache->size);
+
+    for (;;)
+    {
+      if ( *pnode == NULL )
+      {
+        FT_ERROR(( "FreeType.cache.hash_unlink: unknown node !!\n" ));
+        return;
+      }
+
+      if ( *pnode == node )
+      {
+        *pnode     = node->link;
+        node->link = NULL;
+
+        cache->nodes--;
+        return;
+      }
+
+      pnode = &(*pnode)->link;
+    }
+  }
+
+
+ /* add a node to the "top" of its cache's hash table */
+  static void
+  ftc_node_hash_link( FTC_Node   node,
+                      FTC_Cache  cache )
+  {
+    FTC_Node  *pnode = cache->buckets + (node->hash % cache->size);
+
+    node->link = *pnode;
+    *pnode     = node;
+
+    cache->nodes++;
+  }
+
+
+
+
+ /* remove a node from the cache manager */
+  static void
+  ftc_node_destroy( FTC_Node     node,
+                    FTC_Manager  manager )
+  {
+    FT_Memory        memory  = manager->library->memory;
+    FTC_Cache        cache;
+    FTC_Cache_Class  clazz;
+
+#ifdef FT_DEBUG_ERROR
+    /* find node's cache */
+    if ( node->cache_index >= FTC_MAX_CACHES )
+    {
+      FT_ERROR(( "FreeType.cache.node_destroy: invalid node handle\n" ));
+      return;
+    }
+#endif
+
+    cache = manager->caches[ node->cache_index ];
+
+#ifdef FT_DEBUG_ERROR
+    if ( cache == NULL )
+    {
+      FT_ERROR(( "FreeType.cache.node_destroy: invalid node handle\n" ));
+      return;
+    }
+#endif
+
+    clazz = cache->clazz;
+
+    manager->cur_weight -= clazz->node_weight( node, cache );
+
+    /* remove node from mru list */
+    ftc_node_mru_unlink( node, manager );
+
+    /* remove node from cache's hash table */
+    ftc_node_hash_unlink( node, cache );
+
+    /* now finalize it */
+
+    if ( clazz->node_done )
+      clazz->node_done( node, cache );
+
+    FREE( node );
+
+    /* check, just in case of general corruption :-) */
+    if ( manager->num_nodes <= 0 )
+      FT_ERROR(( "FTC_Manager_Compress: Invalid cache node count! = %d\n",
+                  manager->num_nodes ));
+  }
+
+
+
+  FT_EXPORT_DEF(void)
+  FTC_Manager_Check( FTC_Manager  manager )
+  {
+    FTC_Node  node, first;
+    
+    first = manager->nodes_list;
+
+    /* check node weights */
+    if (first)
+    {
+      FT_ULong  weight = 0;
+      
+      node = first;
+      do
+      {
+        FTC_Cache  cache = manager->caches[node->cache_index];
+        
+        weight += cache->clazz->node_weight( node, cache );
+        node = node->mru_next;
+      }
+      while (node != first);
+      
+      if ( weight != manager->cur_weight )
+        FT_ERROR(( "FTC_Manager_Compress: invalid weight %ld instead of %ld\n",
+                   manager->cur_weight, weight ));
+    }
+
+    /* check circular list */
+    if (first)
+    {
+      FT_UFast  count = 0;
+      
+      node = first;
+      do
+      {
+        count++;
+        node = node->mru_next;
+      }
+      while (node != first);
+      
+      if ( count != manager->num_nodes )
+        FT_ERROR(( "FTC_Manager_Compress: invalid cache node count %d instead of %d\n",
+                   manager->num_nodes, count ));
+    }
+  }
+
+
   /* `Compress' the manager's data, i.e., get rid of old cache nodes */
   /* that are not referenced anymore in order to limit the total     */
   /* memory used by the cache.                                       */
@@ -408,70 +670,57 @@
   FT_EXPORT_DEF( void )
   FTC_Manager_Compress( FTC_Manager  manager )
   {
-    FT_ListNode  node;
+    FTC_Node   node, first;
+
+    if ( !manager )
+      return;
+
+    first  = manager->nodes_list;
+
+#if 0
+    FTC_Manager_Check( manager );
+
+    FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
+               manager->cur_weight, manager->max_weight, manager->num_nodes ));
+#endif
 
 
-    node = manager->global_lru.tail;
-    while ( manager->num_bytes > manager->max_bytes && node )
+    if ( manager->cur_weight < manager->max_weight || first == NULL )
+      return;
+
+    /* go to last node - it's a circular list */
+    node = first->mru_prev;
+    do
     {
-      FTC_CacheNode        cache_node = FTC_LIST_TO_CACHENODE( node );
-      FTC_CacheNode_Data*  data       = FTC_CACHENODE_TO_DATA_P( cache_node );
-      FTC_Cache            cache;
-      FT_ListNode          prev       = node->prev;
+      FTC_Node  prev = node->mru_prev;
 
+      prev = ( node == first ) ? NULL : node->mru_prev;
 
-      if ( data->ref_count <= 0 )
-      {
-        /* ok, we are going to remove this node */
-        FT_List_Remove( &manager->global_lru, node );
+      if ( node->ref_count <= 0 )
+        ftc_node_destroy( node, manager );
 
-        /* finalize cache node */
-        cache = manager->caches[data->cache_index];
-        if ( cache )
-        {
-          FTC_CacheNode_Class*  clazz = cache->node_clazz;
-
-
-          manager->num_bytes -= clazz->size_node( cache_node,
-                                                  cache->cache_data );
-
-          clazz->destroy_node( cache_node, cache->cache_data );
-        }
-        else
-        {
-          /* this should never happen! */
-          FT_ERROR(( "FTC_Manager_Compress: Cache Manager is corrupted!\n" ));
-        }
-
-        /* check, just in case of general corruption :-) */
-        if ( manager->num_nodes <= 0 )
-          FT_ERROR(( "FTC_Manager_Compress: Invalid cache node count!\n" ));
-        else
-          manager->num_nodes--;
-      }
       node = prev;
     }
+    while ( node && manager->cur_weight > manager->max_weight );
   }
 
 
+
   FT_EXPORT_DEF( FT_Error )
-  FTC_Manager_Register_Cache( FTC_Manager       manager,
-                              FTC_Cache_Class*  clazz,
-                              FTC_Cache        *acache )
+  FTC_Manager_Register_Cache( FTC_Manager      manager,
+                              FTC_Cache_Class  clazz,
+                              FTC_Cache       *acache )
   {
-    FT_Error  error = FTC_Err_Invalid_Argument;
+    FT_Error   error = FTC_Err_Invalid_Argument;
+    FTC_Cache  cache = NULL;
 
 
     if ( manager && clazz && acache )
     {
       FT_Memory  memory = manager->library->memory;
-      FTC_Cache  cache;
-      FT_UInt    index = 0;
+      FT_UInt    index  = 0;
 
 
-      /* by default, return 0 */
-      *acache = 0;
-
       /* check for an empty cache slot in the manager's table */
       for ( index = 0; index < FTC_MAX_CACHES; index++ )
       {
@@ -488,7 +737,7 @@
         goto Exit;
       }
 
-      if ( !ALLOC( cache, clazz->cache_byte_size ) )
+      if ( !ALLOC( cache, clazz->cache_size ) )
       {
         cache->manager = manager;
         cache->memory  = memory;
@@ -498,19 +747,313 @@
         /* IF IT IS NOT SET CORRECTLY                         */
         cache->cache_index = index;
 
-        if ( clazz->init_cache )
-          error = clazz->init_cache( cache );
+        if ( clazz->cache_init )
+        {
+          error = clazz->cache_init( cache );
+          if ( error )
+          {
+            if ( clazz->cache_done )
+              clazz->cache_done( cache );
 
-        if ( error )
-          FREE( cache );
-        else
-          manager->caches[index] = *acache = cache;
+            FREE( cache );
+            goto Exit;
+          }
+        }
+
+        manager->caches[index] = cache;
       }
     }
 
   Exit:
+    *acache = cache;
     return error;
   }
 
 
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    ABSTRACT CACHE CLASS                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define  FTC_PRIMES_MIN   7
+#define  FTC_PRIMES_MAX   13845163
+
+  static const FT_UInt  ftc_primes[] =
+  {
+    7,
+    11,
+    19,
+    37,
+    73,
+    109,
+    163,
+    251,
+    367,
+    557,
+    823,
+    1237,
+    1861,
+    2777,
+    4177,
+    6247,
+    9371,
+    14057,
+    21089,
+    31627,
+    47431,
+    71143,
+    106721,
+    160073,
+    240101,
+    360163,
+    540217,
+    810343,
+    1215497,
+    1823231,
+    2734867,
+    4102283,
+    6153409,
+    9230113,
+    13845163,
+  };
+
+
+  static FT_UFast
+  ftc_prime_closest( FT_UFast  num )
+  {
+    FT_UInt  i;
+
+    for ( i = 0; i < sizeof(ftc_primes)/sizeof(ftc_primes[0]); i++ )
+      if ( ftc_primes[i] > num )
+        return ftc_primes[i];
+
+    return FTC_PRIMES_MAX;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  ftc_cache_resize( FTC_Cache  cache )
+  {
+    FT_UFast  new_size;
+
+    new_size = ftc_prime_closest( cache->nodes );
+    if ( new_size != cache->size )
+    {
+      FT_Memory  memory = cache->memory;
+      FT_Error   error;
+      FTC_Node*  new_buckets ;
+      FT_ULong   i;
+
+      if ( ALLOC_ARRAY( new_buckets, new_size, FTC_Node ) )
+        return;
+
+      for ( i = 0; i < cache->size; i++ )
+      {
+        FTC_Node   node, next, *pnode;
+        FT_UFast   hash;
+
+        node = cache->buckets[i];
+        while (node)
+        {
+          next  = node->link;
+          hash  = node->hash % new_size;
+          pnode = new_buckets + hash;
+
+          node->link = pnode[0];
+          pnode[0]   = node;
+
+          node  = next;
+        }
+      }
+
+      if ( cache->buckets )
+        FREE( cache->buckets );
+
+      cache->buckets = new_buckets;
+      cache->size    = new_size;
+    }
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  ftc_cache_init( FTC_Cache  cache )
+  {
+    FT_Memory  memory = cache->memory;
+    FT_Error   error;
+    
+    cache->nodes = 0;
+    cache->size  = FTC_PRIMES_MIN;
+    
+    if ( ALLOC_ARRAY( cache->buckets, cache->size, FTC_Node ) )
+      goto Exit;
+      
+  Exit:
+    return error;
+  }
+
+
+
+  FT_EXPORT_DEF( void )
+  ftc_cache_done( FTC_Cache  cache )
+  {
+    if ( cache )
+    {
+      FT_Memory        memory  = cache->memory;
+      FTC_Cache_Class  clazz   = cache->clazz;
+      FTC_Manager      manager = cache->manager;
+      FT_UFast         i;
+
+      for ( i = 0; i < cache->size; i++ )
+      {
+        FTC_Node  *pnode = cache->buckets + i, next, node = *pnode;
+
+        while (node)
+        {
+          next        = node->link;
+          node->link  = NULL;
+
+          /* remove node from mru list */
+          ftc_node_mru_unlink( node, manager );
+
+          /* now finalize it */
+          manager->cur_weight -= clazz->node_weight( node, cache );
+
+          if ( clazz->node_done )
+            clazz->node_done( node, cache );
+
+          FREE( node );
+          node = next;
+        }
+        cache->buckets[i] = NULL;
+      }
+
+      FREE( cache->buckets );
+
+      cache->nodes = 0;
+      cache->size  = 0;
+    }
+  }
+
+
+
+ /* lookup a node  in "top" of its cache's hash table */
+ /* if not found, create a new node..                 */
+ /*                                                   */
+  FT_EXPORT_DEF(FT_Error)
+  ftc_cache_lookup_node( FTC_Cache   cache,
+                         FT_UFast    key_hash,
+                         FT_Pointer  key,
+                         FTC_Node   *anode )
+  {
+    FT_Error   error  = 0;
+    FTC_Node   result = NULL;
+    FTC_Node*  bucket = cache->buckets + (key_hash % cache->size);
+
+    if ( *bucket )
+    {
+      FTC_Node*             pnode   = bucket;
+      FTC_Node_CompareFunc  compare = cache->clazz->node_compare;
+
+      for ( ;; )
+      {
+        FTC_Node  node;
+
+        node = *pnode;
+        if ( node == NULL )
+          break;
+
+        if ( compare( node, key, cache ) )
+        {
+          /* move to head of bucket list */
+          if ( pnode != bucket )
+          {
+            *pnode     = node->link;
+            node->link = *bucket;
+            *bucket    = node;
+          }
+          
+          /* move to head of MRU list */
+          if ( node != cache->manager->nodes_list )
+            ftc_node_mru_up( node, cache->manager );
+
+          result = node;
+          goto Exit;
+        }
+
+        pnode = &(*pnode)->link;
+      }
+    }
+
+    /* didn't find a node, create a new one */
+    {
+      FTC_Cache_Class  clazz   = cache->clazz;
+      FTC_Manager      manager = cache->manager;
+      FT_Memory        memory  = cache->memory;
+      FTC_Node         node;
+
+      if ( ALLOC( node, clazz->node_size ) )
+        goto Exit;
+
+      /* node initializer must set 'hash' field */
+
+      node->cache_index = cache->cache_index;
+      node->ref_count   = 0;
+
+      error = clazz->node_init( node, key, cache );
+      if ( error )
+      {
+        FREE( node );
+        goto Exit;
+      }
+
+      ftc_node_hash_link( node, cache );
+      ftc_node_mru_link( node, cache->manager );
+
+      cache->manager->cur_weight += clazz->node_weight( node, cache );
+
+      /* now try to compress the node pool when necessary */
+      if ( manager->cur_weight >= manager->max_weight )
+      {
+        node->ref_count++;
+        FTC_Manager_Compress( manager );
+        node->ref_count--;
+      }
+
+      /* try to resize the hash table when appropriate */
+      if ( FTC_CACHE_RESIZE_TEST(cache) )
+        ftc_cache_resize( cache );
+
+      result = node;
+    }
+
+  Exit:
+   *anode = result;
+    return error;
+  }
+
+
+ /* maybe these functions will disappear later */
+
+  FT_EXPORT_DEF(void)
+  ftc_node_ref( FTC_Node   node,
+                FTC_Cache  cache )
+  {
+    if ( node && cache && (FT_UInt)node->cache_index == cache->cache_index )
+      node->ref_count++;
+  }
+
+
+
+  FT_EXPORT_DEF(void)
+  ftc_node_unref( FTC_Node   node,
+                  FTC_Cache  cache )
+  {
+    if ( node && cache && (FT_UInt)node->cache_index == cache->cache_index )
+      node->ref_count--;
+  }
+
+
 /* END */
diff --git a/src/cache/ftcsbits.c b/src/cache/ftcsbits.c
index 4b7d25d..871c20c 100644
--- a/src/cache/ftcsbits.c
+++ b/src/cache/ftcsbits.c
@@ -19,6 +19,7 @@
 #include <ft2build.h>
 #include FT_CACHE_H
 #include FT_CACHE_SMALL_BITMAPS_H
+#include FT_CACHE_INTERNAL_CHUNK_H
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_ERRORS_H
@@ -28,23 +29,31 @@
 #include <string.h>         /* memcmp() */
 
 
-#define FTC_SBITSET_ELEMENT_COUNT  16
+#define FTC_SBIT_ITEMS_PER_NODE  16
 
 
+ /* handle to sbit set */
+  typedef struct FTC_SBitSetRec_*   FTC_SBitSet;
+
+ /* sbit set structure */
   typedef struct  FTC_SBitSetRec_
   {
-    FTC_ChunkSetRec  root;
+    FTC_ChunkSetRec  cset;
     FTC_Image_Desc   desc;
 
-  } FTC_SBitSetRec, *FTC_SBitSet;
+  } FTC_SBitSetRec;
+
+#define  FTC_SBIT_SET(x)  ((FTC_SBitSet)(x))
+
+#define  FTC_SBIT_SET_MEMORY(x)  FTC_CHUNK_SET_MEMORY(&(x)->cset)
 
 
-  typedef struct  FTC_SBit_CacheRec_
+  typedef struct FTC_SBitQueryRec_
   {
-    FTC_Chunk_CacheRec  root;
+    FTC_ChunkQueryRec  chunk;
+    FTC_Image_Desc     desc;
 
-  } FTC_SBit_CacheRec;
-
+  } FTC_SBitQueryRec, *FTC_SBitQuery;
 
 
   /*************************************************************************/
@@ -57,77 +66,78 @@
 
 
   FT_CALLBACK_DEF( void )
-  ftc_sbit_chunk_node_destroy( FTC_ChunkNode  node )
+  ftc_sbit_node_done( FTC_ChunkNode  cnode )
   {
-    FTC_ChunkSet  cset   = node->cset;
-    FT_Memory     memory = cset->memory;
-    FT_UInt       count  = node->num_elements;
-    FTC_SBit      sbit   = (FTC_SBit)node->elements;
+    FTC_ChunkSet  cset   = cnode->cset;
+    FT_Memory     memory = cset->ccache->cache.memory;
+    FT_UInt       count  = cnode->item_count;
+    FTC_SBit      sbit   = (FTC_SBit) cnode->items;
 
+    if ( sbit )
+    {
+      for ( ; count > 0; sbit++, count-- )
+        FREE( sbit->buffer );
 
-    for ( ; count > 0; sbit++, count-- )
-      FREE( sbit->buffer );
+      FREE( cnode->items );
+    }
 
-    FREE( node->elements );
-    FREE( node );
+    ftc_chunk_node_done( cnode );
   }
 
 
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_bitmap_copy( FT_Memory   memory,
-                   FT_Bitmap*  source,
-                   FTC_SBit    target )
+  static FT_Error
+  ftc_sbit_set_bitmap( FTC_SBit    sbit,
+                       FT_Bitmap*  bitmap,
+                       FT_Memory   memory )
   {
     FT_Error  error;
-    FT_Int    pitch = source->pitch;
+    FT_Int    pitch = bitmap->pitch;
     FT_ULong  size;
 
 
     if ( pitch < 0 )
       pitch = -pitch;
 
-    size = (FT_ULong)( pitch * source->rows );
+    size = (FT_ULong)( pitch * bitmap->rows );
 
-    if ( !ALLOC( target->buffer, size ) )
-      MEM_Copy( target->buffer, source->buffer, size );
+    if ( !ALLOC( sbit->buffer, size ) )
+      MEM_Copy( sbit->buffer, bitmap->buffer, size );
 
     return error;
   }
 
 
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_sbit_chunk_node_new( FTC_ChunkSet    cset,
-                           FT_UInt         index,
-                           FTC_ChunkNode  *anode )
+
+  static FT_Error
+  ftc_sbit_node_load( FTC_ChunkNode  cnode,
+                      FT_UInt        gindex,
+                      FT_ULong      *asize )
   {
     FT_Error       error;
-    FT_Memory      memory  = cset->memory;
-    FTC_SBitSet    sbitset = (FTC_SBitSet)cset;
-    FTC_ChunkNode  node    = 0;
+    FTC_ChunkSet   cset    = cnode->cset;
+    FTC_SBitSet    sbitset = FTC_SBIT_SET(cset);
+    FT_Memory      memory  = FTC_SBIT_SET_MEMORY(sbitset);
     FT_Face        face;
     FT_Size        size;
 
+    FTC_SBit       sbit;
 
-    /* allocate node */
-    if ( ALLOC( node, sizeof ( *node ) ) )
-      goto Exit;
+    if ( gindex <  (FT_UInt)cnode->item_start                     ||
+         gindex >= (FT_UInt)cnode->item_start + cnode->item_count )
+    {
+      FT_ERROR(( "FreeType.cache.sbit_load: invalid glyph index" ));
+      return FTC_Err_Invalid_Argument;
+    }
 
-    /* initialize its inner fields */
-    error = FTC_ChunkNode_Init( node, cset, index, 1 );
-    if ( error )
-      goto Exit;
+    sbit = (FTC_SBit)cnode->items + (gindex - cnode->item_start);
 
-    /* we will now load all glyph images for this chunk */
-    error = FTC_Manager_Lookup_Size( cset->manager,
+    error = FTC_Manager_Lookup_Size( cset->ccache->cache.manager,
                                      &sbitset->desc.font,
                                      &face, &size );
     if ( !error )
     {
-      FT_UInt   glyph_index = index * cset->element_count;
       FT_UInt   load_flags  = FT_LOAD_DEFAULT;
       FT_UInt   image_type  = sbitset->desc.image_type;
-      FT_UInt   count       = node->num_elements;
-      FTC_SBit  sbit        = (FTC_SBit)node->elements;
 
 
       /* determine load flags, depending on the font description's */
@@ -144,7 +154,7 @@
       }
       else
       {
-        FT_ERROR(( "FTC_SBit_Cache: cannot load scalable glyphs in an"
+        FT_ERROR(( "FreeType.cache.sbit_load: cannot load scalable glyphs in an"
                    " sbit cache, please check your arguments!\n" ));
         error = FTC_Err_Invalid_Argument;
         goto Exit;
@@ -159,102 +169,126 @@
       if ( image_type & ftc_image_flag_autohinted )
         load_flags |= FT_LOAD_FORCE_AUTOHINT;
 
-      /* load a chunk of small bitmaps in a row */
-      for ( ; count > 0; count--, glyph_index++, sbit++ )
+      /* by default, indicates a `missing' glyph */
+      sbit->buffer = 0;
+
+      error = FT_Load_Glyph( face, gindex, load_flags );
+      if ( !error )
       {
-        /* by default, indicates a `missing' glyph */
-        sbit->buffer = 0;
-
-        error = FT_Load_Glyph( face, glyph_index, load_flags );
-        if ( !error )
-        {
-          FT_Int        temp;
-          FT_GlyphSlot  slot   = face->glyph;
-          FT_Bitmap*    bitmap = &slot->bitmap;
-          FT_Int        xadvance, yadvance;
+        FT_Int        temp;
+        FT_GlyphSlot  slot   = face->glyph;
+        FT_Bitmap*    bitmap = &slot->bitmap;
+        FT_Int        xadvance, yadvance;
 
 
-          /* check that our values fit into 8-bit containers!       */
-          /* If this is not the case, our bitmap is too large       */
-          /* and we will leave it as `missing' with sbit.buffer = 0 */
+        /* check that our values fit into 8-bit containers!       */
+        /* If this is not the case, our bitmap is too large       */
+        /* and we will leave it as `missing' with sbit.buffer = 0 */
 
 #define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
 #define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )
 
-          /* XXX: FIXME: add support for vertical layouts maybe */
+        /* XXX: FIXME: add support for vertical layouts maybe */
 
-          /* horizontal advance in pixels */
-          xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
-          yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
+        /* horizontal advance in pixels */
+        xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
+        yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
 
-          if ( CHECK_BYTE( bitmap->rows  )     &&
-               CHECK_BYTE( bitmap->width )     &&
-               CHECK_CHAR( bitmap->pitch )     &&
-               CHECK_CHAR( slot->bitmap_left ) &&
-               CHECK_CHAR( slot->bitmap_top  ) &&
-               CHECK_CHAR( xadvance )          &&
-               CHECK_CHAR( yadvance )          )
+        if ( CHECK_BYTE( bitmap->rows  )     &&
+             CHECK_BYTE( bitmap->width )     &&
+             CHECK_CHAR( bitmap->pitch )     &&
+             CHECK_CHAR( slot->bitmap_left ) &&
+             CHECK_CHAR( slot->bitmap_top  ) &&
+             CHECK_CHAR( xadvance )          &&
+             CHECK_CHAR( yadvance )          )
+        {
+          sbit->width    = (FT_Byte) bitmap->width;
+          sbit->height   = (FT_Byte) bitmap->rows;
+          sbit->pitch    = (FT_Char) bitmap->pitch;
+          sbit->left     = (FT_Char) slot->bitmap_left;
+          sbit->top      = (FT_Char) slot->bitmap_top;
+          sbit->xadvance = (FT_Char) xadvance;
+          sbit->yadvance = (FT_Char) yadvance;
+          sbit->format   = (FT_Byte) bitmap->pixel_mode;
+
+          /* grab the bitmap when possible - this is a hack !! */
+          if ( slot->flags & ft_glyph_own_bitmap )
           {
-            sbit->width    = (FT_Byte)bitmap->width;
-            sbit->height   = (FT_Byte)bitmap->rows;
-            sbit->pitch    = (FT_Char)bitmap->pitch;
-            sbit->left     = (FT_Char)slot->bitmap_left;
-            sbit->top      = (FT_Char)slot->bitmap_top;
-            sbit->xadvance = (FT_Char)xadvance;
-            sbit->yadvance = (FT_Char)yadvance;
-            sbit->format   = (FT_Byte)bitmap->pixel_mode;
-
-            /* grab the bitmap when possible */
-            if ( slot->flags & ft_glyph_own_bitmap )
-            {
-              slot->flags &= ~ft_glyph_own_bitmap;
-              sbit->buffer = bitmap->buffer;
-            }
-            else
-            {
-              /* copy the bitmap into a new buffer -- ignore error */
-              ftc_bitmap_copy( memory, bitmap, sbit );
-            }
+            slot->flags &= ~ft_glyph_own_bitmap;
+            sbit->buffer = bitmap->buffer;
           }
-        }
-      }
+          else
+          {
+            /* copy the bitmap into a new buffer -- ignore error */
+            error = ftc_sbit_set_bitmap( sbit, bitmap, memory );
+          }
+
+          /* now, compute size */
+          if ( asize )
+            *asize = sizeof( FTC_SBitRec ) + ABS(sbit->pitch) * sbit->height;
+          
+        }  /* glyph dimensions ok */
+
+      } /* glyph loading successful */
 
       /* ignore the errors that might have occurred --        */
       /* we recognize unloaded glyphs with `sbit.buffer == 0' */
-      error = 0;
+      /* and 'width == 255', 'height == 0'                    */
+      /*                                                      */
+      if ( error )
+      {
+        sbit->width  = 255;
+        error        = 0;
+        /* sbit->buffer == NULL too !! */
+      }
     }
 
   Exit:
-    if ( error && node )
-    {
-      FREE( node->elements );
-      FREE( node );
-    }
+    return error;
+  }
 
-    *anode = node;
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_sbit_node_init( FTC_ChunkNode   cnode,
+                      FTC_ChunkQuery  query )
+  {
+    FT_Error       error;
+
+    error = ftc_chunk_node_init( cnode,
+                                 query->cset,
+                                 query->gindex,
+                                 TRUE );
+    if ( !error )
+    {
+      error = ftc_sbit_node_load( cnode, query->gindex, NULL );
+
+      if ( error )
+        ftc_chunk_node_done( cnode );
+    }
 
     return error;
   }
 
 
+
   /* this function is important because it is both part of */
   /* an FTC_ChunkSet_Class and an FTC_CacheNode_Class      */
   /*                                                       */
   FT_CALLBACK_DEF( FT_ULong )
-  ftc_sbit_chunk_node_size( FTC_ChunkNode  node )
+  ftc_sbit_node_weight( FTC_ChunkNode  cnode )
   {
     FT_ULong      size;
-    FTC_ChunkSet  cset  = node->cset;
-    FT_UInt       count = node->num_elements;
+    FTC_ChunkSet  cset  = cnode->cset;
+    FT_UInt       count = cnode->item_count;
     FT_Int        pitch;
-    FTC_SBit      sbit  = (FTC_SBit)node->elements;
+    FTC_SBit      sbit  = (FTC_SBit) cnode->items;
 
 
     /* the node itself */
-    size  = sizeof ( *node );
+    size  = sizeof ( *cnode );
 
     /* the sbit records */
-    size += cset->element_count * sizeof ( FTC_SBitRec );
+    size += cnode->item_count * sizeof ( FTC_SBitRec );
 
     for ( ; count > 0; count--, sbit++ )
     {
@@ -273,6 +307,34 @@
   }
 
 
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_sbit_node_compare( FTC_ChunkNode  cnode,
+                         FTC_SBitQuery  query,
+                         FTC_Cache      cache )
+  {
+    FTC_ChunkQuery  creq  = &query->chunk;
+    FT_UInt         gindex = query->chunk.gindex;
+    FT_UInt         offset = (FT_UInt)(gindex - cnode->item_start);
+    FT_Bool         result;
+
+    result = FT_BOOL( offset < (FT_UInt)cnode->item_count &&
+                      creq->cset == cnode->cset );
+    if ( result )
+    {
+      /* check if we need to load the glyph bitmap now */
+      FTC_SBit  sbit = (FTC_SBit)cnode->items + offset;
+      
+      if ( sbit->buffer == NULL && sbit->width != 255 )
+      {
+        FT_ULong  size;
+        ftc_sbit_node_load( cnode, gindex, &size );
+        cache->manager->cur_weight += size;
+      }
+    }
+    return result;
+  }
+
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -283,60 +345,74 @@
 
 
   FT_CALLBACK_DEF( FT_Error )
-  ftc_sbit_chunk_set_sizes( FTC_ChunkSet     cset,
-                            FTC_Image_Desc*  desc )
+  ftc_sbit_set_init( FTC_SBitSet    sset,
+                     FTC_SBitQuery  query,
+                     FT_LruList     lru )
   {
-    FT_Error  error;
-    FT_Face   face;
+    FTC_ChunkCache  ccache  = lru->user_data;
+    FTC_Manager     manager = ccache->cache.manager;
+    FT_Error        error;
+    FT_Face         face;
 
+    sset->desc = query->desc;
 
-    cset->element_count = FTC_SBITSET_ELEMENT_COUNT;
-    cset->element_size  = sizeof ( FTC_SBitRec );
-
-    /* lookup the FT_Face to obtain the number of glyphs */
-    error = FTC_Manager_Lookup_Face( cset->manager,
-                                     desc->font.face_id, &face );
+    /* we need to compute "cquery.item_total" now */
+    error = FTC_Manager_Lookup_Face( manager,
+                                     query->desc.font.face_id,
+                                     &face );
     if ( !error )
-      cset->element_max = face->num_glyphs;
+    {
+      ftc_chunk_set_init( FTC_CHUNK_SET(sset),
+                          sizeof( FTC_SBitRec ),
+                          FTC_SBIT_ITEMS_PER_NODE,
+                          face->num_glyphs,
+                          FTC_CHUNK_CACHE(lru->user_data) );
+
+      /* now compute hash from description - this is _very_ important */
+      /* for good performance..                                       */
+      sset->cset.hash   = FTC_IMAGE_DESC_HASH( &sset->desc );
+      query->chunk.cset = &sset->cset;
+    }
 
     return error;
   }
 
 
-  FT_CALLBACK_DEF( FT_Error )
-  ftc_sbit_chunk_set_init( FTC_SBitSet      sset,
-                           FTC_Image_Desc*  type )
-  {
-    sset->desc = *type;
-
-    return 0;
-  }
-
 
   FT_CALLBACK_DEF( FT_Bool )
-  ftc_sbit_chunk_set_compare( FTC_SBitSet      sset,
-                              FTC_Image_Desc*  type )
+  ftc_sbit_set_compare( FTC_SBitSet    sset,
+                        FTC_SBitQuery  query )
   {
-    return FT_BOOL( !memcmp( &sset->desc, type, sizeof ( *type ) ) );
+    FT_Bool  result;
+
+    /* we need to set the "cquery.cset" field or our query for */
+    /* faster glyph comparisons in ftc_sbit_node_compare..         */
+    /*                                                             */
+    result = FT_BOOL( FTC_IMAGE_DESC_COMPARE( &sset->desc, &query->desc ) );
+    if ( result )
+      query->chunk.cset = &sset->cset;
+
+    return result;
   }
 
 
+
   FT_CALLBACK_TABLE_DEF
-  const FTC_ChunkSet_Class  ftc_sbit_chunk_set_class =
+  const FT_LruList_ClassRec  ftc_sbit_set_class =
   {
+    sizeof( FT_LruListRec ),
+    (FT_LruList_InitFunc)     NULL,
+    (FT_LruList_DoneFunc)     NULL,
+
     sizeof( FTC_SBitSetRec ),
-
-    (FTC_ChunkSet_InitFunc)       ftc_sbit_chunk_set_init,
-    (FTC_ChunkSet_DoneFunc)       0,
-    (FTC_ChunkSet_CompareFunc)    ftc_sbit_chunk_set_compare,
-    (FTC_ChunkSet_SizesFunc)      ftc_sbit_chunk_set_sizes,
-
-    (FTC_ChunkSet_NewNodeFunc)    ftc_sbit_chunk_node_new,
-    (FTC_ChunkSet_SizeNodeFunc)   ftc_sbit_chunk_node_size,
-    (FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy
+    (FT_LruNode_InitFunc)     ftc_sbit_set_init,
+    (FT_LruNode_DoneFunc)     ftc_chunk_set_done,
+    (FT_LruNode_FlushFunc)    NULL,
+    (FT_LruNode_CompareFunc)  ftc_sbit_set_compare,
   };
 
 
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -346,15 +422,25 @@
   /*************************************************************************/
 
 
-  FT_CALLBACK_TABLE_DEF
-  const FTC_Chunk_Cache_Class  ftc_sbit_cache_class =
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_sbit_cache_init( FTC_SBit_Cache  scache )
   {
-    {
-      sizeof( FTC_SBit_CacheRec ),
-      (FTC_Cache_InitFunc)FTC_Chunk_Cache_Init,
-      (FTC_Cache_DoneFunc)FTC_Chunk_Cache_Done
-    },
-    (FTC_ChunkSet_Class*)&ftc_sbit_chunk_set_class
+    return ftc_chunk_cache_init( FTC_CHUNK_CACHE(scache),
+                                 &ftc_sbit_set_class );
+  }
+
+  FT_CALLBACK_TABLE_DEF
+  const FTC_Cache_ClassRec  ftc_sbit_cache_class =
+  {
+    sizeof( FTC_ChunkCacheRec ),
+    (FTC_Cache_InitFunc)  ftc_sbit_cache_init,
+    (FTC_Cache_DoneFunc)  ftc_chunk_cache_done,
+
+    sizeof( FTC_ChunkNodeRec ),
+    (FTC_Node_InitFunc)     ftc_sbit_node_init,
+    (FTC_Node_WeightFunc)   ftc_sbit_node_weight,
+    (FTC_Node_CompareFunc)  ftc_sbit_node_compare,
+    (FTC_Node_DoneFunc)     ftc_sbit_node_done
   };
 
 
@@ -366,8 +452,8 @@
   {
     return FTC_Manager_Register_Cache(
              manager,
-             (FTC_Cache_Class*)&ftc_sbit_cache_class,
-             (FTC_Cache*)acache );
+             &ftc_sbit_cache_class,
+             (FTC_Cache*) acache );
   }
 
 
@@ -379,21 +465,27 @@
                          FT_UInt          gindex,
                          FTC_SBit        *ansbit )
   {
-    FT_Error       error;
-    FTC_ChunkNode  node;
-    FT_UInt        cindex;
+    FT_Error          error;
+    FTC_ChunkCache    ccache = (FTC_ChunkCache) cache;
+    FTC_ChunkNode     node;
+    FTC_SBitQueryRec  query;
 
 
     /* argument checks delayed to FTC_Chunk_Cache_Lookup */
     if ( !ansbit )
       return FTC_Err_Invalid_Argument;
 
-    *ansbit = 0;
-    error   = FTC_Chunk_Cache_Lookup( &cache->root, desc, gindex,
-                                      &node, &cindex );
-    if ( !error )
-      *ansbit = (FTC_SBit)node->elements + cindex;
+    *ansbit = NULL;
 
+    query.chunk.gindex = gindex;
+    query.chunk.cset   = NULL;
+    query.desc         = *desc;
+    
+    error = ftc_chunk_cache_lookup( ccache, &query.chunk, &node );
+    if ( !error )
+    {
+      *ansbit = (FTC_SBit) node->items + (gindex - node->item_start);
+    }
     return error;
   }
 
diff --git a/src/cache/ftlru.c b/src/cache/ftlru.c
index 2838847..eed41f5 100644
--- a/src/cache/ftlru.c
+++ b/src/cache/ftlru.c
@@ -25,326 +25,308 @@
 #include "ftcerror.h"
 
 
-  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_DEF( FT_Error )
-  FT_Lru_New( const FT_Lru_Class*  clazz,
-              FT_UInt              max_elements,
-              FT_Pointer           user_data,
-              FT_Memory            memory,
-              FT_Bool              pre_alloc,
-              FT_Lru              *anlru )
+  FT_LruList_New( FT_LruList_Class  clazz,
+                  FT_UInt           max_nodes,
+                  FT_Pointer        user_data,
+                  FT_Memory         memory,
+                  FT_LruList       *alist )
   {
-    FT_Error  error;
-    FT_Lru    lru;
+    FT_Error    error;
+    FT_LruList  list;
 
-
-    if ( !anlru )
+    if ( !alist || !clazz )
       return FTC_Err_Invalid_Argument;
 
-    *anlru = 0;
-    if ( !ALLOC( lru, sizeof ( *lru ) ) )
+    *alist = NULL;
+    if ( !ALLOC( list, clazz->list_size ) )
     {
-      if ( pre_alloc )
-      {
-        /* allocate static array of lru list nodes */
-        if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) )
-        {
-          FREE( lru );
-          goto Exit;
-        }
+      /* initialize common fields */
+      list->clazz      = clazz;
+      list->memory     = memory;
+      list->max_nodes  = max_nodes;
+      list->user_data  = user_data;
 
-        /* build the `free_nodes' list from the array */
-        lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes );
+      if ( clazz->list_init )
+      {
+        error = clazz->list_init( list );
+        if ( error )
+        {
+          if ( clazz->list_done )
+            clazz->list_done( list );
+
+          FREE( list );
+        }
       }
 
-      /* initialize common fields */
-      lru->clazz        = (FT_Lru_Class*)clazz;
-      lru->max_elements = max_elements;
-      lru->memory       = memory;
-      lru->user_data    = user_data;
-
-      *anlru = lru;
+      *alist = list;
     }
 
-  Exit:
     return error;
   }
 
 
   FT_EXPORT_DEF( void )
-  FT_Lru_Reset( FT_Lru  lru )
+  FT_LruList_Destroy( FT_LruList  list )
   {
-    FT_ListNode    node;
-    FT_Lru_Class*  clazz;
-    FT_Memory      memory;
+    FT_Memory         memory;
+    FT_LruList_Class  clazz;
 
-
-    if ( !lru )
+    if ( !list )
       return;
 
-    node   = lru->elements.head;
-    clazz  = lru->clazz;
-    memory = lru->memory;
+    memory = list->memory;
+    clazz  = list->clazz;
 
-    while ( node )
-    {
-      FT_ListNode  next = node->next;
+    FT_LruList_Reset( list );
 
+    if ( clazz->list_done )
+      clazz->list_done( list );
 
-      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;
+    FREE( list );
   }
 
 
+
   FT_EXPORT_DEF( void )
-  FT_Lru_Done( FT_Lru  lru )
+  FT_LruList_Reset( FT_LruList  list )
   {
-    FT_Memory  memory;
+    FT_LruNode        node;
+    FT_LruList_Class  clazz;
+    FT_Memory         memory;
 
 
-    if ( !lru )
+    if ( !list )
       return;
 
-    memory = lru->memory;
+    node   = list->nodes;
+    clazz  = list->clazz;
+    memory = list->memory;
 
-    FT_Lru_Reset( lru );
+    while ( node )
+    {
+      FT_LruNode  next = node->next;
 
-    FREE( lru->nodes );
-    FREE( lru );
+      if ( clazz->node_done )
+        clazz->node_done( node, list );
+
+      FREE( node );
+      node = next;
+    }
+
+    list->nodes     = NULL;
+    list->num_nodes = 0;
   }
 
 
   FT_EXPORT_DEF( FT_Error )
-  FT_Lru_Lookup_Node( FT_Lru       lru,
-                      FT_LruKey    key,
-                      FT_LruNode  *anode )
+  FT_LruList_Lookup( FT_LruList   list,
+                     FT_LruKey    key,
+                     FT_LruNode  *anode )
   {
-    FT_Error       error = 0;
-    FT_ListNode    node;
-    FT_Lru_Class*  clazz;
-    FT_LruNode     found = 0;
-    FT_Memory      memory;
+    FT_Error          error = 0;
+    FT_LruNode        node, *pnode;
+    FT_LruList_Class  clazz;
+    FT_LruNode*       plast;
+    FT_LruNode        result = NULL;
+    FT_Memory         memory;
 
 
-    if ( !lru || !key || !anode )
+    if ( !list || !key || !anode )
       return FTC_Err_Invalid_Argument;
 
-    node   = lru->elements.head;
-    clazz  = lru->clazz;
-    memory = lru->memory;
+    pnode  = &list->nodes;
+    plast  = pnode;
+    node   = NULL;
+    clazz  = list->clazz;
+    memory = list->memory;
 
-    if ( clazz->compare_element )
+    if ( clazz->node_compare )
     {
-      for ( ; node; node = node->next )
-        if ( clazz->compare_element( (FT_LruNode)node, key ) )
-        {
-          found = (FT_LruNode)node;
+      for (;;)
+      {
+        node = *pnode;
+        if ( node == NULL )
           break;
-        }
+
+        if ( clazz->node_compare( node, key, list ) )
+          break;
+
+        plast = pnode;
+        pnode = &(*pnode)->next;
+      }
     }
     else
     {
-      for ( ; node; node = node->next )
-        if ( ((FT_LruNode)node)->key == key )
-        {
-          found = (FT_LruNode)node;
+      for (;;)
+      {
+        node = *pnode;
+        if ( node == NULL )
           break;
-        }
+
+        if ( node->key == key )
+          break;
+
+        plast = pnode;
+        pnode = &(*pnode)->next;
+      }
     }
 
-    if ( found )
+    if ( node )
     {
       /* move element to top of list */
-      FT_List_Up( &lru->elements, node );
-    }
-    else
-    {
-      /* we haven't found the relevant element.  We will now try */
-      /* to create a new one.                                    */
-      if ( lru->num_elements >= lru->max_elements )
+      if ( list->nodes != node )
       {
-        /* this lru list is full; we will now flush */
-        /* the oldest node                          */
-        FT_LruNode  lru_node;
+        *pnode      = node->next;
+        node->next  = list->nodes;
+        list->nodes  = node;
+      }
+      result = node;
+      goto Exit;
+    }
 
+    /* we haven't found the relevant element.  We will now try */
+    /* to create a new one.                                    */
+    /*                                                         */
 
-        node     = lru->elements.tail;
-        lru_node = (FT_LruNode)node;
-        found    = lru_node;
+    /* first, check if our list if full, when appropriate */
+    if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes )
+    {
+      /* this list list is full; we will now flush */
+      /* the oldest node, if there's one !!       */
+      FT_LruNode  last = *plast;
 
-        if ( clazz->flush_element )
-          error = clazz->flush_element( lru, lru_node, key );
+      if ( last )
+      {
+        if ( clazz->node_flush )
+        {
+          error = clazz->node_flush( last, key, list );
+        }
         else
         {
-          clazz->done_element( lru, lru_node );
-          lru_node->key = key;
-          node->data    = 0;
-          error = clazz->init_element( lru, lru_node );
+          if ( clazz->node_done )
+            clazz->node_done( last, list );
+
+          last->key  = key;
+          error = clazz->node_init( last, key, list );
         }
 
         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--;
+          /* move it to the top of the list */
+          *plast      = NULL;
+          last->next  = list->nodes;
+          list->nodes = last;
 
-          if ( lru->nodes )
-            FT_List_Insert( &lru->free_nodes, node );
-          else
-            FREE( lru_node );
-
-          found = 0;
-        }
-      }
-      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;
-          }
+          result = last;
+          goto Exit;
         }
 
-        found = lru_node;
-        node  = (FT_ListNode)lru_node;
-        FT_List_Insert( &lru->elements, node );
-        lru->num_elements++;
+        /* in case of error during the flush or done/init cycle, */
+        /* we need to discard the node..                         */
+        if ( clazz->node_done )
+          clazz->node_done( last, list );
+
+        *plast = NULL;
+        list->num_nodes--;
+
+        FREE( last );
+        goto Exit;
       }
     }
 
+    /* otherwise, simply allocate a new node */
+    if ( ALLOC( node, clazz->node_size ) )
+      goto Exit;
+
+    node->key = key;
+    error = clazz->node_init( node, key, list );
+    if ( error )
+    {
+      FREE( node );
+      goto Exit;
+    }
+
+    result      = node;
+    node->next  = list->nodes;
+    list->nodes = node;
+    list->num_nodes++;
+
   Exit:
-    *anode = found;
+    *anode = result;
     return error;
   }
 
 
-  FT_EXPORT_DEF( FT_Error )
-  FT_Lru_Lookup( FT_Lru       lru,
-                 FT_LruKey    key,
-                 FT_Pointer  *anobject )
-  {
-    FT_Error    error;
-    FT_LruNode  node;
-
-
-    /* check for valid `lru' and `key' delayed to FT_Lru_Lookup_Node() */
-
-    if ( !anobject )
-      return FTC_Err_Invalid_Argument;
-
-    *anobject = 0;
-    error = FT_Lru_Lookup_Node( lru, key, &node );
-    if ( !error )
-      *anobject = node->root.data;
-
-    return error;
-  }
-
 
   FT_EXPORT_DEF( void )
-  FT_Lru_Remove_Node( FT_Lru      lru,
-                      FT_LruNode  node )
+  FT_LruList_Remove( FT_LruList  list,
+                     FT_LruNode  node )
   {
-    if ( !lru || !node )
+    FT_LruNode  *pnode;
+
+    if ( !list || !node )
       return;
 
-    if ( lru->num_elements > 0 )
+    pnode = &list->nodes;
+    for (;;)
     {
-      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
+      if ( *pnode == node )
       {
-        FT_Memory  memory = lru->memory;
+        FT_Memory         memory = list->memory;
+        FT_LruList_Class  clazz  = list->clazz;
 
+        *pnode     = node->next;
+        node->next = NULL;
+
+        if ( clazz->node_done )
+          clazz->node_done( node, list );
+
+        FREE( node );
+        list->num_nodes--;
+        break;
+      }
+
+      pnode = &(*pnode)->next;
+    }
+  }
+
+
+
+  FT_EXPORT_DEF( void )
+  FT_LruList_Remove_Selection( FT_LruList             list,
+                               FT_LruNode_SelectFunc  select_func,
+                               FT_Pointer             select_data )
+  {
+    FT_LruNode       *pnode, node;
+    FT_LruList_Class  clazz;
+    FT_Memory         memory;
+
+    if ( !list || !select_func )
+      return;
+
+    memory = list->memory;
+    clazz  = list->clazz;
+    pnode  = &list->nodes;
+
+    for (;;)
+    {
+      node = *pnode;
+      if ( node == NULL )
+        break;
+
+      if ( select_func( node, select_data, list ) )
+      {
+        *pnode     = node->next;
+        node->next = NULL;
+
+        if ( clazz->node_done )
+          clazz->node_done( node, list );
 
         FREE( node );
       }
-
-      lru->num_elements--;
-    }
-  }
-
-
-  FT_EXPORT_DEF( void )
-  FT_Lru_Remove_Selection( FT_Lru           lru,
-                           FT_Lru_Selector  selector,
-                           FT_Pointer       data )
-  {
-    if ( !lru || !selector )
-      return;
-
-    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;
-      }
+      else
+        pnode = &(*pnode)->next;
     }
   }