#include "a.h" struct Cache { CEntry **hash; int nhash; CEntry *head; CEntry *tail; int nentry; int maxentry; int sizeofentry; void (*cefree)(CEntry*); }; static void nop(CEntry *ce) { } static uint hash(const char *s) { uint h; uchar *p; h = 0; for(p=(uchar*)s; *p; p++) h = h*37 + *p; return h; } Cache* newcache(int sizeofentry, int maxentry, void (*cefree)(CEntry*)) { Cache *c; int i; assert(sizeofentry >= sizeof(CEntry)); c = emalloc(sizeof *c); c->sizeofentry = sizeofentry; c->maxentry = maxentry; c->nentry = 0; for(i=1; inhash = i; c->hash = emalloc(c->nhash * sizeof c->hash[0]); if(cefree == nil) cefree = nop; c->cefree = cefree; return c; } static void popout(Cache *c, CEntry *e) { if(e->list.prev) e->list.prev->list.next = e->list.next; else c->head = e->list.next; if(e->list.next) e->list.next->list.prev = e->list.prev; else c->tail = e->list.prev; } static void insertfront(Cache *c, CEntry *e) { e->list.next = c->head; c->head = e; if(e->list.next) e->list.next->list.prev = e; else c->tail = e; } static void movetofront(Cache *c, CEntry *e) { popout(c, e); insertfront(c, e); } static CEntry* evict(Cache *c) { CEntry *e; e = c->tail; popout(c, e); c->cefree(e); free(e->name); e->name = nil; memset(e, 0, c->sizeofentry); insertfront(c, e); return e; } CEntry* cachelookup(Cache *c, char *name, int create) { int h; CEntry *e; h = hash(name) % c->nhash; for(e=c->hash[h]; e; e=e->hash.next){ if(strcmp(name, e->name) == 0){ movetofront(c, e); return e; } } if(!create) return nil; if(c->nentry >= c->maxentry) e = evict(c); else{ e = emalloc(c->sizeofentry); insertfront(c, e); c->nentry++; } e->name = estrdup(name); h = hash(name) % c->nhash; e->hash.next = c->hash[h]; c->hash[h] = e; return e; } void cacheflush(Cache *c, char *substr) { CEntry **l, *e; int i; for(i=0; inhash; i++){ for(l=&c->hash[i]; (e=*l); ){ if(substr == nil || strstr(e->name, substr)){ *l = e->hash.next; c->nentry--; popout(c, e); c->cefree(e); free(e->name); free(e); }else l = &e->hash.next; } } }