#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);