/* * The flatcc builder supports storing a pointer to a refmap * and wraps some operations to make them work as a dummy * even if no refmap has been set. This enables optional * DAG preservation possible during clone operations. * * A refmap maps a source address to a builder reference. * * This is just a map, but the semantics are important: * * The map thus preserves identity of the source. It is not a * cache because cache eviction would fail to properly track * identity. * * The map is used for memoization during object cloning are and * may also be used by user logic doing similar operations. * This ensures that identity is preserved so a source object is * not duplicated which could lead to either loss of semantic * information, or an explosion in size, or both. In some, or * even most, cases this concern may not be important, but when * it is important, it is important. * * The source address must not be reused for different content * for the lifetime of the map, although the content doest not * have to be valid or event exist at that location since source * address is just used as a key. * * The lifetime may be a single clone operation which then * tracks child object references as well, or it may be the * lifetime of the buffer builder. * * The map may be flushed explicitly when the source addresses * are no longer unique, such as when reusing a memory buffer, * and when identity preservation is no longer important. * Flushing a map is esentially the same as ending a lifetime. * * Multiple maps may exist concurrently for example if cloning * an object twice into two new objects that should have * separate identities. This is especially true and necessary * when creating a new nested buffer because the nested buffer * cannot share references with the parent. Cloning and object * that contains a nested buffer does not require multiple maps * because the nested buffer is then opaque. */ #ifndef FLATCC_REFMAP_H #define FLATCC_REFMAP_H #ifdef __cplusplus extern "C" { #endif #include "flatcc_types.h" #ifndef FLATCC_REFMAP_MIN_BUCKETS /* 8 buckets gives us 5 useful initial entries with a load factor of 0.7 */ #define FLATCC_REFMAP_MIN_BUCKETS 8 #endif #define FLATCC_REFMAP_LOAD_FACTOR 0.7f typedef struct flatcc_refmap flatcc_refmap_t; typedef flatbuffers_soffset_t flatcc_refmap_ref_t; static const flatcc_refmap_ref_t flatcc_refmap_not_found = 0; struct flatcc_refmap_item { const void *src; flatcc_refmap_ref_t ref; }; struct flatcc_refmap { size_t count; size_t buckets; struct flatcc_refmap_item *table; /* Use stack allocation for small maps. */ struct flatcc_refmap_item min_table[FLATCC_REFMAP_MIN_BUCKETS]; }; /* * Fast zero initialization - does not allocate any memory. * May be replaced by memset 0, but `init` avoids clearing the * stack allocated initial hash table until it is needed. */ static inline int flatcc_refmap_init(flatcc_refmap_t *refmap) { refmap->count = 0; refmap->buckets = 0; refmap->table = 0; return 0; } /* * Removes all items and deallocates memory. * Not required unless `insert` or `resize` took place. The map can be * reused subsequently without calling `init`. */ void flatcc_refmap_clear(flatcc_refmap_t *refmap); /* * Keeps allocated memory as is, but removes all items. The map * must intialized first. */ void flatcc_refmap_reset(flatcc_refmap_t *refmap); /* * Returns the inserted reference if the `src` pointer was found, * without inspecting the content of the `src` pointer. * * Returns flatcc_refmap_not_found (default 0) if the `src` pointer was * not found. */ flatcc_refmap_ref_t flatcc_refmap_find(flatcc_refmap_t *refmap, const void *src); /* * Inserts a `src` source pointer and its associated `ref` reference * into the refmap without inspecting the `src` pointer content. The * `ref` value will be replaced if the the `src` pointer already exists. * * Inserting null will just return the ref without updating the map. * * There is no delete operation which simplifies an open * addressing hash table, and it isn't needed for this use case. * * Returns the input ref or not_found on allocation error. */ flatcc_refmap_ref_t flatcc_refmap_insert(flatcc_refmap_t *refmap, const void *src, flatcc_refmap_ref_t ref); /* * Set the hash table to accommodate at least `count` items while staying * within the predefined load factor. * * Resize is primarily an internal operation, but the user may resize * ahead of a large anticipated load, or after a large load to shrink * the table using 0 as the `count` argument. The table never shrinks * on its own account. */ int flatcc_refmap_resize(flatcc_refmap_t *refmap, size_t count); #ifdef __cplusplus } #endif #endif /* FLATCC_REFMAP_H */