Annotation of embedaddon/php/ext/gd/libgd/gdcache.c, revision 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>