#Index Mapped Array (iMap)
#define FIO_IMAP_CORE
#include "fio-stl.h"A macro-generated hash-map-backed array. Keeps insertion order in a dense array while the index map provides near-O(1) lookups. Mostly used internally by other STL modules; for public map needs see FIO_MAP_NAME.
Note: iMap does not manage object lifetimes. Clean up stored resources before calling destroy.
#Configuration Macros
#FIO_TYPEDEF_IMAP_REALLOC
#ifndef FIO_TYPEDEF_IMAP_REALLOC
#define FIO_TYPEDEF_IMAP_REALLOC FIO_MEM_REALLOC
#endifAllocator used for iMap growth. Defaults to FIO_MEM_REALLOC.
#FIO_TYPEDEF_IMAP_REALLOC_IS_SAFE
#ifndef FIO_TYPEDEF_IMAP_REALLOC_IS_SAFE
#define FIO_TYPEDEF_IMAP_REALLOC_IS_SAFE FIO_MEM_REALLOC_IS_SAFE
#endifSet if the realloc zeroes new memory; otherwise iMap zeroes it explicitly.
#FIO_TYPEDEF_IMAP_FREE
#ifndef FIO_TYPEDEF_IMAP_FREE
#define FIO_TYPEDEF_IMAP_FREE FIO_MEM_FREE
#endifDeallocator used by array_name_destroy.
#Helper Macros
#FIO_IMAP_ALWAYS_VALID
#define FIO_IMAP_ALWAYS_VALID(o) (1)Validity helper that treats every object as valid.
#FIO_IMAP_VALID_NON_ZERO
#define FIO_IMAP_VALID_NON_ZERO(o) (!!((o)[0]))Validity helper that treats an object as valid if its first element is non-zero.
#FIO_IMAP_ALWAYS_CMP_TRUE / FIO_IMAP_ALWAYS_CMP_FALSE
#define FIO_IMAP_ALWAYS_CMP_TRUE(a, b) (1)
#define FIO_IMAP_ALWAYS_CMP_FALSE(a, b) (0)Comparison helpers that always return true or false.
#FIO_IMAP_SIMPLE_CMP
#define FIO_IMAP_SIMPLE_CMP(a, b) ((a)[0] == (b)[0])Compares two objects by their first element.
#FIO_IMAP_EACH
#define FIO_IMAP_EACH(array_name, map_ptr, i) \
for (size_t i = 0; i < (map_ptr)->w; ++i) \
if (!FIO_NAME(array_name, is_valid)((map_ptr)->ary + i)) \
continue; \
elseIterates valid elements in insertion order. Use it as a loop header:
FIO_IMAP_EACH(my_map, &map, i) {
printf("%llu\n", (unsigned long long)map.ary[i].key);
}#Type Definition Macro
#FIO_TYPEDEF_IMAP_ARRAY
#define FIO_TYPEDEF_IMAP_ARRAY(array_name, \
array_type, \
imap_type, \
hash_fn, \
cmp_fn, \
is_valid_fn)Generates the iMap container type and functions prefixed with array_name. The callbacks take pointers to elements:
hash_fn(pobj)returns animap_typehash.cmp_fn(a_ptr, b_ptr)returns non-zero on match.is_valid_fn(pobj)returns non-zero if the element is valid.
Reserved index-map values: 0 means empty, ~0 means freed.
#Generated Types
#array_name_s
typedef struct {
array_type *ary;
imap_type count;
imap_type w;
uint32_t capa_bits;
} array_name_s;ary— dense array of elements.count— number of valid (non-removed) elements.w— next write position / logical size.capa_bits— log2 of capacity; actual capacity is1 << capa_bits.
#array_name_seeker_s
typedef struct {
imap_type pos;
imap_type ipos;
imap_type set_val;
} array_name_seeker_s;pos— array index, orwif not found.ipos— index-map slot, or~0if no room.set_val— value to write into the index map on insert.
#Generated Functions
#array_name_is_valid
FIO_IFUNC int array_name_is_valid(array_type *pobj);Wraps the is_valid_fn supplied to the macro.
#array_name_capa
FIO_IFUNC size_t array_name_capa(array_name_s *a);Returns 1 << a->capa_bits, or 0 if not allocated.
#array_name_imap
FIO_IFUNC imap_type *array_name_imap(array_name_s *a);Returns a pointer to the index map stored immediately after the array.
#array_name_destroy
FIO_IFUNC void array_name_destroy(array_name_s *a);Frees the array + index map and zeros the container. Does not run destructors on elements.
#array_name_seek
FIO_SFUNC array_name_seeker_s array_name_seek(array_name_s *a,
array_type *pobj);Finds an element or the place to insert it.
#array_name_reserve
FIO_IFUNC int array_name_reserve(array_name_s *a, imap_type min);Grows the backing storage to at least min slots. Returns 0 on success, -1 on failure.
#array_name_rehash
FIO_IFUNC int array_name_rehash(array_name_s *a);Rebuilds the index map from the current array contents. Call after sorting or other position-changing operations. Returns 0 on success, -1 on failure.
#array_name_set
FIO_IFUNC array_type *array_name_set(array_name_s *a,
array_type obj,
int overwrite);Inserts or updates an element. If overwrite is zero and the key already exists, returns the existing element. Returns a pointer to the stored element or NULL on failure.
#array_name_get
FIO_IFUNC array_type *array_name_get(array_name_s *a, array_type obj);Looks up an element. Returns a pointer to the match or NULL.
#array_name_remove
FIO_IFUNC int array_name_remove(array_name_s *a, array_type obj);Zeros the matching element and marks its index-map slot as freed. Returns 0 on success, -1 if not found.
#Internal Seeker Types
#fio___imapN_seeker_s
typedef struct {
uintN_t pos;
uintN_t ipos;
uintN_t set_val;
bool is_valid;
} fio___imapN_seeker_s;Where N is 8, 16, 32, or 64. Low-level seeker used by other STL internals.
#fio___imapN_seek
FIO_SFUNC fio___imapN_seeker_s fio___imapN_seek(
void *ary,
uintN_t *imap,
const uintN_t capa_bits,
void *pobj,
uintN_t hash,
bool cmp_fn(void *arry, void *obj, uintN_t indx),
const size_t max_attempts);Low-level seek through an index map. Generally used internally.
#fio___imapN_set
FIO_IFUNC void fio___imapN_set(uintN_t *imap,
uintN_t ipos,
uintN_t set_val);Writes set_val into imap[ipos].
#Example
#define FIO_IMAP_CORE
#include "fio-stl.h"
typedef struct { uint64_t key; int value; } kv_s;
static uint64_t kv_hash(kv_s *p) { return fio_risky_num(p->key, 0); }
static int kv_cmp(kv_s *a, kv_s *b) { return a->key == b->key; }
static int kv_valid(kv_s *p) { return p->key != 0; }
FIO_TYPEDEF_IMAP_ARRAY(kv, kv_s, uint32_t, kv_hash, kv_cmp, kv_valid)
int main(void) {
kv_s map = {0};
kv_set(&map, (kv_s){.key = 1, .value = 100}, 1);
kv_set(&map, (kv_s){.key = 2, .value = 200}, 1);
kv_s *found = kv_get(&map, (kv_s){.key = 2});
if (found) printf("value: %d\n", found->value);
FIO_IMAP_EACH(kv, &map, i) {
printf("%llu -> %d\n",
(unsigned long long)map.ary[i].key, map.ary[i].value);
}
kv_remove(&map, (kv_s){.key = 2});
kv_destroy(&map);
return 0;
}