#pragma once #include "type.h" #define mapValue_null ((mapValue){.p=nullptr}) #ifndef _mapValue_size #define _mapValue_size ( \ sizeof(intmax_t) > sizeof(double) ? \ sizeof(intmax_t) : sizeof(double) \ ) #endif typedef union mapValue { /* ensure proper alignment & offer convenience * handles for punning */ size_t sz; ptrdiff_t ofs; intptr_t ip; uintmax_t u; intmax_t s; double d; void * p; void const* p_ro; char * str; char const* str_ro; uint8_t* bytes; uint8_t const* bytes_ro; /* maps can pack very small structures directly into * the entry. if you use this feature, either define * _mapValue_size as a project global yourself, or * check to make sure your values fit into it on a * given architecture. i think this is guaranteed * to have at least 8 bytes of space (64-types are * mandated as of C11, possibly earleir?) but i'm * not 100% on that.*/ char str_pak [_mapValue_size]; uint8_t bytes_pak [_mapValue_size]; } mapValue; typedef struct mapLink { struct mapLink* next, * prev; mapValue ref; strv key; } mapLink; typedef struct mapBox { mapLink* head, * tail; } mapBox; typedef typeof(bool (*)(mapValue, void*)) mapPredicate; typedef typeof(void (*)(mapValue)) mapDTor; typedef struct map { size_t sz; //bool weak; mapDTor dtor; mapBox boxes []; } map; typedef struct mapResult { map* map; mapBox* box; mapLink* link; } mapResult; map* mapNew(size_t init_sz); mapBox* mapBoxFor(map* map, strp key); void mapBoxInsert(mapBox* b, mapLink* l); mapLink* mapEnter(map* m, strp key, mapValue val); bool mapClobber(map* m, strp key, mapValue val, mapDTor dtor); mapResult mapFind(map* map, strp key); mapValue mapRef(map* m, strp key); mapResult mapRFindPred(map* map, void* arg, mapPredicate match); mapResult mapRFind(map* m, mapValue val); strp mapRRefPred(map* m, void* val, mapPredicate p); strp mapRRef(map* m, mapValue val); void mapErase(map* map, strp key); map* mapDel(map* map); map* mapResize(map* map, size_t newsz);