150 lines
2.1 KiB
C
150 lines
2.1 KiB
C
|
|
#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; i<maxentry; i<<=1)
|
||
|
|
;
|
||
|
|
c->nhash = 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; i<c->nhash; 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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|