#include "map.h" #include 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); }