#include "map.h"
#include <stdlib.h>
map* mapNew(size_t init_sz) {
map* m = malloc(
sizeof(map) +
sizeof(mapBox)*init_sz
);
m -> sz = init_sz;
m -> dtor = nullptr;
for (size_t i = 0; i < init_sz; ++i)
m -> boxes[i] = (mapBox) {};
//m -> weak = false;
return m;
}
mapBox* mapBoxFor(map* m, strp key) {
hash h = hashNew(key);
return &m->boxes[h % (hash)m->sz];
}
void mapBoxInsert(mapBox* b, mapLink* l) {
l -> next = nullptr;
l -> prev = b -> tail;
if (b -> tail == nullptr) {
b -> head = b -> tail = l;
} else {
b -> tail -> next = l;
b -> tail = l;
}
}
mapLink* mapEnter(map* m, strp key, mapValue val) {
mapResult r = mapFind(m, key);
if (r.link) {
return r.link;
} else {
mapBox* b = r.box;
mapLink* l = malloc(sizeof(mapLink) + key.sz);
l -> ref = val;
strMov(&l -> key, key);
mapBoxInsert(b, l);
//if(!m->weak) vspRef(val);
return nullptr;
}
}
bool mapClobber(map* m, strp key, mapValue val, void (*dtor)(mapValue)) {
mapLink* link = mapEnter(m, key, val);
if (link) {
if (!dtor) dtor = m -> dtor;
if (dtor) (*dtor)(link -> ref);
link -> ref = val;
return true;
}
return false;
}
mapResult mapFind(map* m, strp key) {
mapBox* b = mapBoxFor(m, key);
for(mapLink* l = b -> head; l != nullptr;) {
if(strEq(strRef(&l->key), key)) {
return (mapResult) {
.map = m,
.box = b,
.link = l,
};
}
}
return (mapResult){.map = m, .box = b};
}
mapValue mapRef(map* m, strp key) {
mapResult r = mapFind(m, key);
if (r.link == nullptr) return mapValue_null;
return r.link -> ref;
}
void mapErase(map* m, strp key) {
mapResult r = mapFind(m, key);
if (r.link -> prev) r.link -> prev -> next = r.link -> next;
if (r.link -> next) r.link -> next -> prev = r.link -> prev;
if (r.box -> head == r.link) r.box -> head = r.link -> next;
if (r.box -> tail == r.link) r.box -> tail = r.link -> prev;
//if (!m -> weak) vspUnref(r.link -> ref);
free(r.link);
}
map* mapDel(map* m) {
for (size_t i = 0; i < m -> sz; ++i) {
mapBox* b = &m->boxes[i];
if (b -> head == nullptr) continue;
for(mapLink* l = b -> head; l != nullptr;) {
mapLink* next = l -> next;
//if(!m->weak) vspUnref(l->ref);
free(l);
l = next;
}
}
free(m);
}
map* mapResize(map* om, size_t newsz) {
/* expensive!! */
map* nm = mapNew(newsz);
//nm -> weak = om -> weak;
for (size_t i = 0; i < om -> sz; ++i) {
mapBox* b = &om->boxes[i];
if (b -> head == nullptr) continue;
for(mapLink* l = b -> head; l != nullptr;) {
mapBox* nb = mapBoxFor(nm, strRef(&l->key));
mapBoxInsert(nb, l);
}
}
free(om);
return nm;
}
static bool mapEqPredicate(mapValue a, void* b) {
return a.ip = ((mapValue*)b) -> ip; /* real fucky */
}
mapResult mapRFindPred(map* m, void* val, mapPredicate p) {
for (size_t i = 0; i < m->sz; ++ i) {
mapBox* b = &m -> boxes[i];
if (b -> head == nullptr) continue;
for (mapLink* l = b -> head; l != nullptr; l = l -> next) {
if ((*p)(l->ref, val)) return (mapResult) {
.map = m,
.box = b,
.link = l,
};
}
}
return (mapResult) {m};
}
mapResult mapRFind(map* m, mapValue val) {
return mapRFindPred(m, &val, mapEqPredicate);
}
strp mapRRefPred(map* m, void* val, mapPredicate p) {
mapResult r = mapRFindPred(m, val, p);
if (r.link == nullptr) return (strp){};
return strRef(&r.link -> key);
}
strp mapRRef(map* m, mapValue val) {
return mapRRefPred(m, &val, mapEqPredicate);
}