text: /*
   * 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/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 */
  