Annotation of embedaddon/php/ext/gd/libgd/gdcache.c, revision 1.1.1.1

1.1       misho       1: #include "gd.h"
                      2: #include "gdhelpers.h"
                      3: 
                      4: #ifdef HAVE_LIBFREETYPE
                      5: #define NEED_CACHE 1
                      6: #endif
                      7: 
                      8: #ifdef NEED_CACHE
                      9: 
                     10: /*
                     11:  * gdcache.c
                     12:  *
                     13:  * Caches of pointers to user structs in which the least-recently-used
                     14:  * element is replaced in the event of a cache miss after the cache has
                     15:  * reached a given size.
                     16:  *
                     17:  * John Ellson  (ellson@graphviz.org)  Oct 31, 1997
                     18:  *
                     19:  * Test this with:
                     20:  *               gcc -o gdcache -g -Wall -DTEST gdcache.c
                     21:  *
                     22:  * The cache is implemented by a singly-linked list of elements
                     23:  * each containing a pointer to a user struct that is being managed by
                     24:  * the cache.
                     25:  *
                     26:  * The head structure has a pointer to the most-recently-used
                     27:  * element, and elements are moved to this position in the list each
                     28:  * time they are used.  The head also contains pointers to three
                     29:  * user defined functions:
                     30:  *              - a function to test if a cached userdata matches some keydata
                     31:  *              - a function to provide a new userdata struct to the cache
                     32:  *          if there has been a cache miss.
                     33:  *              - a function to release a userdata struct when it is
                     34:  *          no longer being managed by the cache
                     35:  *
                     36:  * In the event of a cache miss the cache is allowed to grow up to
                     37:  * a specified maximum size.  After the maximum size is reached then
                     38:  * the least-recently-used element is discarded to make room for the
                     39:  * new.  The most-recently-returned value is always left at the
                     40:  * beginning of the list after retrieval.
                     41:  *
                     42:  * In the current implementation the cache is traversed by a linear
                     43:  * search from most-recent to least-recent.  This linear search
                     44:  * probably limits the usefulness of this implementation to cache
                     45:  * sizes of a few tens of elements.
                     46:  */
                     47: 
                     48: #include "gdcache.h"
                     49: 
                     50: /*********************************************************/
                     51: /* implementation                                        */
                     52: /*********************************************************/
                     53: 
                     54: 
                     55: /* create a new cache */
                     56: gdCache_head_t *
                     57: gdCacheCreate (
                     58:                int size,
                     59:                gdCacheTestFn_t gdCacheTest,
                     60:                gdCacheFetchFn_t gdCacheFetch,
                     61:                gdCacheReleaseFn_t gdCacheRelease)
                     62: {
                     63:   gdCache_head_t *head;
                     64: 
                     65:   head = (gdCache_head_t *) gdPMalloc(sizeof (gdCache_head_t));
                     66:   head->mru = NULL;
                     67:   head->size = size;
                     68:   head->gdCacheTest = gdCacheTest;
                     69:   head->gdCacheFetch = gdCacheFetch;
                     70:   head->gdCacheRelease = gdCacheRelease;
                     71:   return head;
                     72: }
                     73: 
                     74: void
                     75: gdCacheDelete (gdCache_head_t * head)
                     76: {
                     77:   gdCache_element_t *elem, *prev;
                     78: 
                     79:   elem = head->mru;
                     80:   while (elem)
                     81:     {
                     82:       (*(head->gdCacheRelease)) (elem->userdata);
                     83:       prev = elem;
                     84:       elem = elem->next;
                     85:       gdPFree ((char *) prev);
                     86:     }
                     87:   gdPFree ((char *) head);
                     88: }
                     89: 
                     90: void *
                     91: gdCacheGet (gdCache_head_t * head, void *keydata)
                     92: {
                     93:   int i = 0;
                     94:   gdCache_element_t *elem, *prev = NULL, *prevprev = NULL;
                     95:   void *userdata;
                     96: 
                     97:   elem = head->mru;
                     98:   while (elem)
                     99:     {
                    100:       if ((*(head->gdCacheTest)) (elem->userdata, keydata))
                    101:        {
                    102:          if (i)
                    103:            {                   /* if not already most-recently-used */
                    104:              /* relink to top of list */
                    105:              prev->next = elem->next;
                    106:              elem->next = head->mru;
                    107:              head->mru = elem;
                    108:            }
                    109:          return elem->userdata;
                    110:        }
                    111:       prevprev = prev;
                    112:       prev = elem;
                    113:       elem = elem->next;
                    114:       i++;
                    115:     }
                    116:   userdata = (*(head->gdCacheFetch)) (&(head->error), keydata);
                    117:   if (!userdata)
                    118:     {
                    119:       /* if there was an error in the fetch then don't cache */
                    120:       return NULL;
                    121:     }
                    122:   if (i < head->size)
                    123:     {                          /* cache still growing - add new elem */
                    124:       elem = (gdCache_element_t *) gdPMalloc(sizeof (gdCache_element_t));
                    125:     }
                    126:   else
                    127:     {                          /* cache full - replace least-recently-used */
                    128:       /* preveprev becomes new end of list */
                    129:       prevprev->next = NULL;
                    130:       elem = prev;
                    131:       (*(head->gdCacheRelease)) (elem->userdata);
                    132:     }
                    133:   /* relink to top of list */
                    134:   elem->next = head->mru;
                    135:   head->mru = elem;
                    136:   elem->userdata = userdata;
                    137:   return userdata;
                    138: }
                    139: 
                    140: 
                    141: 
                    142: /*********************************************************/
                    143: /* test stub                                             */
                    144: /*********************************************************/
                    145: 
                    146: 
                    147: #ifdef TEST
                    148: 
                    149: #include <stdio.h>
                    150: 
                    151: typedef struct
                    152: {
                    153:   int key;
                    154:   int value;
                    155: }
                    156: key_value_t;
                    157: 
                    158: static int
                    159: cacheTest (void *map, void *key)
                    160: {
                    161:   return (((key_value_t *) map)->key == *(int *) key);
                    162: }
                    163: 
                    164: static void *
                    165: cacheFetch (char **error, void *key)
                    166: {
                    167:   key_value_t *map;
                    168: 
                    169:   map = (key_value_t *) gdMalloc (sizeof (key_value_t));
                    170:   map->key = *(int *) key;
                    171:   map->value = 3;
                    172: 
                    173:   *error = NULL;
                    174:   return (void *) map;
                    175: }
                    176: 
                    177: static void
                    178: cacheRelease (void *map)
                    179: {
                    180:   gdFree ((char *) map);
                    181: }
                    182: 
                    183: int
                    184: main (char *argv[], int argc)
                    185: {
                    186:   gdCache_head_t *cacheTable;
                    187:   int elem, key;
                    188: 
                    189:   cacheTable = gdCacheCreate (3, cacheTest, cacheFetch, cacheRelease);
                    190: 
                    191:   key = 20;
                    192:   elem = *(int *) gdCacheGet (cacheTable, &key);
                    193:   key = 30;
                    194:   elem = *(int *) gdCacheGet (cacheTable, &key);
                    195:   key = 40;
                    196:   elem = *(int *) gdCacheGet (cacheTable, &key);
                    197:   key = 50;
                    198:   elem = *(int *) gdCacheGet (cacheTable, &key);
                    199:   key = 30;
                    200:   elem = *(int *) gdCacheGet (cacheTable, &key);
                    201:   key = 30;
                    202:   elem = *(int *) gdCacheGet (cacheTable, &key);
                    203: 
                    204:   gdCacheDelete (cacheTable);
                    205: 
                    206:   return 0;
                    207: }
                    208: 
                    209: #endif /* TEST */
                    210: #endif /* HAVE_NEECACHE */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>