You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
4.0 KiB
C

#include "imap.h"
#include "profile.h"
enum imap_status {
IS_NONE,
IS_EXIST,
IS_REMOVE,
};
struct imap_slot {
uint64_t key;
void* value;
enum imap_status status;
struct imap_slot* next;
};
struct imap_context {
struct imap_slot* slots;
size_t size;
size_t count;
struct imap_slot* lastfree;
};
#define DEFAULT_IMAP_SLOT_SIZE 1024
struct imap_context *
imap_create() {
struct imap_context* imap = (struct imap_context*)pmalloc(sizeof(*imap));
imap->slots = (struct imap_slot*)pcalloc(DEFAULT_IMAP_SLOT_SIZE, sizeof(struct imap_slot));
imap->size = DEFAULT_IMAP_SLOT_SIZE;
imap->count = 0;
imap->lastfree = imap->slots + imap->size;
return imap;
}
void
imap_free(struct imap_context* imap) {
pfree(imap->slots);
pfree(imap);
}
static inline uint64_t
_imap_hash(struct imap_context* imap, uint64_t key) {
uint64_t hash = key % (uint64_t)(imap->size);
return hash;
}
static void
_imap_rehash(struct imap_context* imap) {
size_t new_sz = DEFAULT_IMAP_SLOT_SIZE;
struct imap_slot* old_slots = imap->slots;
size_t old_count = imap->count;
size_t old_size = imap->size;
while(new_sz <= imap->count) {
new_sz *= 2;
}
struct imap_slot* new_slots = (struct imap_slot*)pcalloc(new_sz, sizeof(struct imap_slot));
imap->lastfree = new_slots + new_sz;
imap->size = new_sz;
imap->slots = new_slots;
imap->count = 0;
size_t i=0;
for(i=0; i<old_size; i++) {
struct imap_slot* p = &(old_slots[i]);
enum imap_status status = p->status;
if(status == IS_EXIST) {
imap_set(imap, p->key, p->value);
}
}
assert(old_count == imap->count);
pfree(old_slots);
}
static struct imap_slot *
_imap_query(struct imap_context* imap, uint64_t key) {
uint64_t hash = _imap_hash(imap, key);
struct imap_slot* p = &(imap->slots[hash]);
if(p->status != IS_NONE) {
while(p) {
if(p->key == key && p->status == IS_EXIST) {
return p;
}
p = p->next;
}
}
return NULL;
}
void *
imap_query(struct imap_context* imap, uint64_t key) {
struct imap_slot* p = _imap_query(imap, key);
if(p) {
return p->value;
}
return NULL;
}
static struct imap_slot *
_imap_getfree(struct imap_context* imap) {
while(imap->lastfree > imap->slots) {
imap->lastfree--;
if(imap->lastfree->status == IS_NONE) {
return imap->lastfree;
}
}
return NULL;
}
void
imap_set(struct imap_context* imap, uint64_t key, void* value) {
assert(value);
uint64_t hash = _imap_hash(imap, key);
struct imap_slot* p = &(imap->slots[hash]);
if(p->status == IS_EXIST) {
struct imap_slot* np = p;
while(np) {
if(np->key == key && np->status == IS_EXIST) {
np->value = value;
return;
}
np = np->next;
}
np = _imap_getfree(imap);
if(np == NULL) {
_imap_rehash(imap);
imap_set(imap, key, value);
return;
}
uint64_t main_hash = _imap_hash(imap, p->key);
np->next = p->next;
p->next = np;
if(main_hash == hash) {
p = np;
}else {
np->key = p->key;
np->value = p->value;
np->status = IS_EXIST;
}
}
imap->count++;
p->status = IS_EXIST;
p->key = key;
p->value = value;
}
void *
imap_remove(struct imap_context* imap, uint64_t key) {
struct imap_slot* p = _imap_query(imap, key);
if(p) {
imap->count--;
p->status = IS_REMOVE;
return p->value;
}
return NULL;
}
void
imap_dump(struct imap_context* imap, observer observer_cb, void* ud) {
size_t i=0;
for(i=0; i<imap->size; i++) {
struct imap_slot* v = &imap->slots[i];
if(v->status == IS_EXIST) {
observer_cb(v->key, v->value, ud);
}
}
}
size_t
imap_size(struct imap_context* imap) {
return imap->count;
}