C Container Collection (CCC)
|
The Flat Hash Map Interface. More...
Go to the source code of this file.
Initialization Interface | |
Initialize the container with memory, callbacks, and permissions. | |
#define | ccc_fhm_init(memory_ptr, capacity, fhash_elem_field, key_field, alloc_fn, hash_fn, key_eq_fn, aux_data) |
Initialize a map with a buffer of types at compile time or runtime. | |
ccc_result | ccc_fhm_copy (ccc_flat_hash_map *dst, ccc_flat_hash_map const *src, ccc_alloc_fn *fn) |
Copy the map at source to destination. | |
Entry Interface | |
Obtain and operate on container entries for efficient queries when non-trivial control flow is needed. | |
#define | ccc_fhm_insert_r(flat_hash_map_ptr, out_handle_ptr) |
Invariantly inserts the key value wrapping out_handle_ptr. | |
#define | ccc_fhm_remove_r(flat_hash_map_ptr, out_handle_ptr) |
Removes the key value in the map storing the old value, if present, in the struct containing out_handle_ptr provided by the user. | |
#define | ccc_fhm_try_insert_r(flat_hash_map_ptr, key_val_handle_ptr) |
Attempts to insert the key value wrapping key_val_handle_ptr. | |
#define | ccc_fhm_try_insert_w(flat_hash_map_ptr, key, lazy_value...) |
lazily insert lazy_value into the map at key if key is absent. | |
#define | ccc_fhm_insert_or_assign_r(flat_hash_map_ptr, key_val_handle_ptr) |
Invariantly inserts or overwrites a user struct into the table. | |
#define | ccc_fhm_insert_or_assign_w(flat_hash_map_ptr, key, lazy_value...) |
Inserts a new key value pair or overwrites the existing entry. | |
#define | ccc_fhm_entry_r(flat_hash_map_ptr, key_ptr) |
Obtains an entry for the provided key in the table for future use. | |
#define | ccc_fhm_and_modify_w(flat_hash_map_entry_ptr, type_name, closure_over_T...) |
Modify an Occupied entry with a closure over user type T. | |
#define | ccc_fhm_or_insert_w(flat_hash_map_entry_ptr, lazy_key_value...) ccc_impl_fhm_or_insert_w(flat_hash_map_entry_ptr, lazy_key_value) |
lazily insert the desired key value into the entry if it is Vacant. | |
#define | ccc_fhm_insert_entry_w(flat_hash_map_entry_ptr, lazy_key_value...) ccc_impl_fhm_insert_entry_w(flat_hash_map_entry_ptr, lazy_key_value) |
write the contents of the compound literal lazy_key_value to a slot. | |
#define | ccc_fhm_remove_entry_r(flat_hash_map_entry_ptr) |
Remove the entry from the table if Occupied. | |
ccc_entry | ccc_fhm_insert (ccc_flat_hash_map *h, ccc_fhmap_elem *out_handle) |
Invariantly inserts the key value wrapping out_handle. | |
ccc_entry | ccc_fhm_remove (ccc_flat_hash_map *h, ccc_fhmap_elem *out_handle) |
Removes the key value in the map storing the old value, if present, in the struct containing out_handle provided by the user. | |
ccc_entry | ccc_fhm_try_insert (ccc_flat_hash_map *h, ccc_fhmap_elem *key_val_handle) |
Attempts to insert the key value wrapping key_val_handle. | |
ccc_entry | ccc_fhm_insert_or_assign (ccc_flat_hash_map *h, ccc_fhmap_elem *key_val_handle) |
Invariantly inserts or overwrites a user struct into the table. | |
ccc_fhmap_entry | ccc_fhm_entry (ccc_flat_hash_map *h, void const *key) |
Obtains an entry for the provided key in the table for future use. | |
ccc_fhmap_entry * | ccc_fhm_and_modify (ccc_fhmap_entry *e, ccc_update_fn *fn) |
Modifies the provided entry if it is Occupied. | |
ccc_fhmap_entry * | ccc_fhm_and_modify_aux (ccc_fhmap_entry *e, ccc_update_fn *fn, void *aux) |
Modifies the provided entry if it is Occupied. | |
void * | ccc_fhm_or_insert (ccc_fhmap_entry const *e, ccc_fhmap_elem *elem) |
Inserts the struct with handle elem if the entry is Vacant. | |
void * | ccc_fhm_insert_entry (ccc_fhmap_entry const *e, ccc_fhmap_elem *elem) |
Inserts the provided entry invariantly. | |
ccc_entry | ccc_fhm_remove_entry (ccc_fhmap_entry const *e) |
Remove the entry from the table if Occupied. | |
void * | ccc_fhm_unwrap (ccc_fhmap_entry const *e) |
Unwraps the provided entry to obtain a view into the table element. | |
bool | ccc_fhm_occupied (ccc_fhmap_entry const *e) |
Returns the Vacant or Occupied status of the entry. | |
bool | ccc_fhm_insert_error (ccc_fhmap_entry const *e) |
Provides the status of the entry should an insertion follow. | |
ccc_entry_status | ccc_fhm_entry_status (ccc_fhmap_entry const *e) |
Obtain the entry status from a container entry. | |
Container Types | |
Types available in the container interface. | |
typedef struct ccc_fhmap_ | ccc_flat_hash_map |
A container for storing key-value structures defined by the user in a contiguous buffer. | |
typedef struct ccc_fhmap_elem_ | ccc_fhmap_elem |
An intrusive element for a user provided type. | |
typedef union ccc_fhmap_entry_ | ccc_fhmap_entry |
A container specific entry used to implement the Entry Interface. | |
Membership Interface | |
Test membership or obtain references to stored user types directly. | |
bool | ccc_fhm_contains (ccc_flat_hash_map *h, void const *key) |
Searches the table for the presence of key. | |
void * | ccc_fhm_get_key_val (ccc_flat_hash_map *h, void const *key) |
Returns a reference into the table at entry key. | |
Deallocation Interface | |
Destroy the container. | |
ccc_result | ccc_fhm_clear (ccc_flat_hash_map *h, ccc_destructor_fn *fn) |
Frees all slots in the table for use without affecting capacity. | |
ccc_result | ccc_fhm_clear_and_free (ccc_flat_hash_map *h, ccc_destructor_fn *fn) |
Frees all slots in the table and frees the underlying buffer. | |
Iterator Interface | |
Obtain and manage iterators over the container. | |
void * | ccc_fhm_begin (ccc_flat_hash_map const *h) |
Obtains a pointer to the first element in the table. | |
void * | ccc_fhm_next (ccc_flat_hash_map const *h, ccc_fhmap_elem const *iter) |
Advances the iterator to the next occupied table slot. | |
void * | ccc_fhm_end (ccc_flat_hash_map const *h) |
Check the current iterator against the end for loop termination. | |
State Interface | |
Obtain the container state. | |
bool | ccc_fhm_is_empty (ccc_flat_hash_map const *h) |
Returns the size status of the table. | |
size_t | ccc_fhm_size (ccc_flat_hash_map const *h) |
Returns the size of the table. | |
size_t | ccc_fhm_next_prime (size_t n) |
Helper to find a prime number if needed. | |
size_t | ccc_fhm_capacity (ccc_flat_hash_map const *h) |
Return the full capacity of the backing storage. | |
void * | ccc_fhm_data (ccc_flat_hash_map const *h) |
Return a reference to the base of backing array. O(1). | |
bool | ccc_fhm_validate (ccc_flat_hash_map const *h) |
Validation of invariants for the hash table. | |
The Flat Hash Map Interface.
A Flat Hash Map stores elements by hash value and allows the user to retrieve them by key in amortized O(1). Elements in the table may be copied and moved so no pointer stability is available in this implementation. If pointer stability is needed, store and hash pointers to those elements in this table.
A flat hash map requires the user to provide a struct with known key and flat hash element fields as well as a hash function and key comparator function. The hash function should be well tailored to the key being stored in the table to prevent collisions. Currently, the flat hash map does not offer any default hash functions or hash strengthening algorithms so strong hash functions should be obtained by the user for the data set.
To shorten names in the interface, define the following preprocessor directive at the top of your file.
All types and functions can then be written without the ccc_
prefix.
#define ccc_fhm_and_modify_w | ( | flat_hash_map_entry_ptr, | |
type_name, | |||
closure_over_T... | |||
) |
Modify an Occupied entry with a closure over user type T.
[in] | flat_hash_map_entry_ptr | a pointer to the obtained entry. |
[in] | type_name | the name of the user type stored in the container. |
[in] | closure_over_T | the code to be run on the reference to user type T, if Occupied. This may be a semicolon separated list of statements to execute on T or a section of code wrapped in braces {code here} which may be preferred for formatting. |
Note that any code written is only evaluated if the entry is Occupied and the container can deliver the user type T. This means any function calls are lazily evaluated in the closure scope.
#define ccc_fhm_entry_r | ( | flat_hash_map_ptr, | |
key_ptr | |||
) |
Obtains an entry for the provided key in the table for future use.
[in] | flat_hash_map_ptr | the hash table to be searched. |
[in] | key_ptr | the key used to search the table matching the stored key type. |
An entry is a search result that provides either an Occupied or Vacant entry in the table. An occupied entry signifies that the search was successful. A Vacant entry means the search was not successful but we now have a handle to where in the table such an element should be inserted.
An entry is most often passed in a functional style to subsequent calls in the Entry Interface.
#define ccc_fhm_init | ( | memory_ptr, | |
capacity, | |||
fhash_elem_field, | |||
key_field, | |||
alloc_fn, | |||
hash_fn, | |||
key_eq_fn, | |||
aux_data | |||
) |
Initialize a map with a buffer of types at compile time or runtime.
[in] | memory_ptr | the pointer to the backing buffer array of user types. May be NULL if the user provides a allocation function. The buffer will be interpreted in units of type size that the user intends to store. |
[in] | capacity | the starting capacity of the provided buffer or 0 if no buffer is provided and an allocation function is given. |
[in] | fhash_elem_field | the name of the fhmap_elem field. |
[in] | key_field | the field of the struct used for key storage. |
[in] | alloc_fn | the allocation function for resizing or NULL if no resizing is allowed. |
[in] | hash_fn | the ccc_hash_fn function the user desires for the table. |
[in] | key_eq_fn | the ccc_key_eq_fn the user intends to use. |
[in] | aux_data | auxiliary data that is needed for hashing or comparison. |
#define ccc_fhm_insert_entry_w | ( | flat_hash_map_entry_ptr, | |
lazy_key_value... | |||
) | ccc_impl_fhm_insert_entry_w(flat_hash_map_entry_ptr, lazy_key_value) |
write the contents of the compound literal lazy_key_value to a slot.
[in] | flat_hash_map_entry_ptr | a pointer to the obtained entry. |
[in] | lazy_key_value | the compound literal to write to a new slot. |
#define ccc_fhm_insert_or_assign_r | ( | flat_hash_map_ptr, | |
key_val_handle_ptr | |||
) |
Invariantly inserts or overwrites a user struct into the table.
[in] | flat_hash_map_ptr | a pointer to the flat hash map. |
[in] | key_val_handle_ptr | the handle to the wrapping user struct key value. |
Note that this function can be used when the old user type is not needed but the information regarding its presence is helpful.
#define ccc_fhm_insert_or_assign_w | ( | flat_hash_map_ptr, | |
key, | |||
lazy_value... | |||
) |
Inserts a new key value pair or overwrites the existing entry.
[in] | flat_hash_map_ptr | the pointer to the flat hash map. |
[in] | key | the key to be searched in the table. |
[in] | lazy_value | the compound literal to insert or use for overwrite. |
Note that for brevity and convenience the user need not write the key to the lazy value compound literal as well. This function ensures the key in the compound literal matches the searched key.
#define ccc_fhm_insert_r | ( | flat_hash_map_ptr, | |
out_handle_ptr | |||
) |
Invariantly inserts the key value wrapping out_handle_ptr.
[in] | flat_hash_map_ptr | the pointer to the flat hash map. |
[out] | out_handle_ptr | the handle to the user type wrapping fhash elem. |
Note that this function may write to the struct containing the second parameter and wraps it in an entry to provide information about the old value.
#define ccc_fhm_or_insert_w | ( | flat_hash_map_entry_ptr, | |
lazy_key_value... | |||
) | ccc_impl_fhm_or_insert_w(flat_hash_map_entry_ptr, lazy_key_value) |
lazily insert the desired key value into the entry if it is Vacant.
[in] | flat_hash_map_entry_ptr | a pointer to the obtained entry. |
[in] | lazy_key_value | the compound literal to construct in place if the entry is Vacant. |
Note that if the compound literal uses any function calls to generate values or other data, such functions will not be called if the entry is Occupied.
#define ccc_fhm_remove_entry_r | ( | flat_hash_map_entry_ptr | ) |
Remove the entry from the table if Occupied.
[in] | flat_hash_map_entry_ptr | a pointer to the table entry. |
#define ccc_fhm_remove_r | ( | flat_hash_map_ptr, | |
out_handle_ptr | |||
) |
Removes the key value in the map storing the old value, if present, in the struct containing out_handle_ptr provided by the user.
[in] | flat_hash_map_ptr | the pointer to the flat hash map. |
[out] | out_handle_ptr | the handle to the user type wrapping fhash elem. |
Note that this function may write to the struct containing the second parameter and wraps it in an entry to provide information about the old value.
#define ccc_fhm_try_insert_r | ( | flat_hash_map_ptr, | |
key_val_handle_ptr | |||
) |
Attempts to insert the key value wrapping key_val_handle_ptr.
[in] | flat_hash_map_ptr | the pointer to the flat hash map. |
[in] | key_val_handle_ptr | the handle to the user type wrapping fhash elem. |
#define ccc_fhm_try_insert_w | ( | flat_hash_map_ptr, | |
key, | |||
lazy_value... | |||
) |
lazily insert lazy_value into the map at key if key is absent.
[in] | flat_hash_map_ptr | a pointer to the flat hash map. |
[in] | key | the direct key r-value. |
[in] | lazy_value | the compound literal specifying the value. |
int
and you pass a size_t
variable to the key argument, you will overwrite adjacent bytes of your struct.Note that for brevity and convenience the user need not write the key to the lazy value compound literal as well. This function ensures the key in the compound literal matches the searched key.
typedef struct ccc_fhmap_elem_ ccc_fhmap_elem |
An intrusive element for a user provided type.
Because the hash map is flat, data is always copied from the provided type into the table.
typedef union ccc_fhmap_entry_ ccc_fhmap_entry |
A container specific entry used to implement the Entry Interface.
The Entry Interface offers efficient search and subsequent insertion, deletion, or value update based on the needs of the user.
typedef struct ccc_fhmap_ ccc_flat_hash_map |
A container for storing key-value structures defined by the user in a contiguous buffer.
A flat hash map can be initialized on the stack, heap, or data segment at runtime.
ccc_fhmap_entry * ccc_fhm_and_modify | ( | ccc_fhmap_entry * | e, |
ccc_update_fn * | fn | ||
) |
Modifies the provided entry if it is Occupied.
[in] | e | the entry obtained from an entry function or macro. |
[in] | fn | an update function in which the auxiliary argument is unused. |
This function is intended to make the function chaining in the Entry Interface more succinct if the entry will be modified in place based on its own value without the need of the auxiliary argument a ccc_update_fn can provide.
ccc_fhmap_entry * ccc_fhm_and_modify_aux | ( | ccc_fhmap_entry * | e, |
ccc_update_fn * | fn, | ||
void * | aux | ||
) |
Modifies the provided entry if it is Occupied.
[in] | e | the entry obtained from an entry function or macro. |
[in] | fn | an update function that requires auxiliary data. |
[in] | aux | auxiliary data required for the update. |
This function makes full use of a ccc_update_fn capability, meaning a complete ccc_update object will be passed to the update function callback.
void * ccc_fhm_begin | ( | ccc_flat_hash_map const * | h | ) |
Obtains a pointer to the first element in the table.
[in] | h | the table to iterate through. |
Iteration starts from index 0 by capacity of the table so iteration order is not obvious to the user, nor should any specific order be relied on.
size_t ccc_fhm_capacity | ( | ccc_flat_hash_map const * | h | ) |
Return the full capacity of the backing storage.
[in] | h | the hash table. |
ccc_result ccc_fhm_clear | ( | ccc_flat_hash_map * | h, |
ccc_destructor_fn * | fn | ||
) |
Frees all slots in the table for use without affecting capacity.
[in] | h | the table to be cleared. |
[in] | fn | the destructor for each element. NULL can be passed if no maintenance is required on the elements in the table before their slots are forfeit. |
If NULL is passed as the destructor function time is O(1), else O(capacity).
ccc_result ccc_fhm_clear_and_free | ( | ccc_flat_hash_map * | h, |
ccc_destructor_fn * | fn | ||
) |
Frees all slots in the table and frees the underlying buffer.
[in] | h | the table to be cleared. |
[in] | fn | the destructor for each element. NULL can be passed if no maintenance is required on the elements in the table before their slots are forfeit. |
bool ccc_fhm_contains | ( | ccc_flat_hash_map * | h, |
void const * | key | ||
) |
Searches the table for the presence of key.
[in] | h | the flat hash table to be searched. |
[in] | key | pointer to the key matching the key type of the user struct. |
ccc_result ccc_fhm_copy | ( | ccc_flat_hash_map * | dst, |
ccc_flat_hash_map const * | src, | ||
ccc_alloc_fn * | fn | ||
) |
Copy the map at source to destination.
[in] | dst | the initialized destination for the copy of the src map. |
[in] | src | the initialized source of the map. |
[in] | fn | the optional allocation function if resizing is needed. |
Note that there are two ways to copy data from source to destination: provide sufficient memory and pass NULL as fn, or allow the copy function to take care of allocation for the copy.
Manual memory management with no allocation function provided.
The above requires dst capacity be greater than or equal to src capacity. Here is memory management handed over to the copy function.
The above allows dst to have a capacity less than that of the src as long as copy has been provided an allocation function to resize dst. Note that this would still work if copying to a destination that the user wants as a fixed size map.
The above sets up dst with fixed size while src is a dynamic map. Because an allocation function is provided, the dst is resized once for the copy and retains its fixed size after the copy is complete. This would require the user to manually free the underlying buffer at dst eventually if this method is used. Usually it is better to allocate the memory explicitly before the copy if copying between maps without allocation permission.
These options allow users to stay consistent across containers with their memory management strategies.
void * ccc_fhm_data | ( | ccc_flat_hash_map const * | h | ) |
Return a reference to the base of backing array. O(1).
[in] | h | a pointer to the map. |
void * ccc_fhm_end | ( | ccc_flat_hash_map const * | h | ) |
Check the current iterator against the end for loop termination.
[in] | h | the table being iterated upon. |
ccc_fhmap_entry ccc_fhm_entry | ( | ccc_flat_hash_map * | h, |
void const * | key | ||
) |
Obtains an entry for the provided key in the table for future use.
[in] | h | the hash table to be searched. |
[in] | key | the key used to search the table matching the stored key type. |
An entry is a search result that provides either an Occupied or Vacant entry in the table. An occupied entry signifies that the search was successful. A Vacant entry means the search was not successful but we now have a handle to where in the table such an element should be inserted.
An entry is rarely useful on its own. It should be passed in a functional style to subsequent calls in the Entry Interface.
ccc_entry_status ccc_fhm_entry_status | ( | ccc_fhmap_entry const * | e | ) |
Obtain the entry status from a container entry.
[in] | e | a pointer to the entry. |
Note that this function can be useful for debugging or if more detailed messages are needed for logging purposes. See ccc_entry_status_msg() in ccc/types.h for more information on detailed entry statuses.
void * ccc_fhm_get_key_val | ( | ccc_flat_hash_map * | h, |
void const * | key | ||
) |
Returns a reference into the table at entry key.
[in] | h | the flat hash map to search. |
[in] | key | the key to search matching stored key type. |
ccc_entry ccc_fhm_insert | ( | ccc_flat_hash_map * | h, |
ccc_fhmap_elem * | out_handle | ||
) |
Invariantly inserts the key value wrapping out_handle.
[in] | h | the pointer to the flat hash map. |
[out] | out_handle | the handle to the user type wrapping fhash elem. |
Note that this function may write to the struct containing the second parameter and wraps it in an entry to provide information about the old value.
void * ccc_fhm_insert_entry | ( | ccc_fhmap_entry const * | e, |
ccc_fhmap_elem * | elem | ||
) |
Inserts the provided entry invariantly.
[in] | e | the entry returned from a call obtaining an entry. |
[in] | elem | a handle to the struct the user intends to insert. |
This method can be used when the old value in the table does not need to be preserved. See the regular insert method if the old value is of interest. If an error occurs during the insertion process due to memory limitations or a search error NULL is returned. Otherwise insertion should not fail.
bool ccc_fhm_insert_error | ( | ccc_fhmap_entry const * | e | ) |
Provides the status of the entry should an insertion follow.
[in] | e | the entry from a query to the table via function or macro. |
Table resizing occurs upon calls to entry functions/macros or when trying to insert a new element directly. This is to provide stable entries from the time they are obtained to the time they are used in functions they are passed to (i.e. the idiomatic or_insert(entry(...)...)).
However, if a Vacant entry is returned and then a subsequent insertion function is used, it will not work if resizing has failed and the return of those functions will indicate such a failure. One can also confirm an insertion error will occur from an entry with this function. For example, leaving this function in an assert for debug builds can be a helpful sanity check if the heap should correctly resize by default and errors are not usually expected.
ccc_entry ccc_fhm_insert_or_assign | ( | ccc_flat_hash_map * | h, |
ccc_fhmap_elem * | key_val_handle | ||
) |
Invariantly inserts or overwrites a user struct into the table.
[in] | h | a pointer to the flat hash map. |
[in] | key_val_handle | the handle to the wrapping user struct key value. |
Note that this function can be used when the old user type is not needed but the information regarding its presence is helpful.
bool ccc_fhm_is_empty | ( | ccc_flat_hash_map const * | h | ) |
Returns the size status of the table.
[in] | h | the hash table. |
void * ccc_fhm_next | ( | ccc_flat_hash_map const * | h, |
ccc_fhmap_elem const * | iter | ||
) |
Advances the iterator to the next occupied table slot.
[in] | h | the table being iterated upon. |
[in] | iter | the previous iterator. |
size_t ccc_fhm_next_prime | ( | size_t | n | ) |
Helper to find a prime number if needed.
[in] | n | the input that may or may not be prime. |
It is possible to use this hash table without an allocator by providing the buffer to be used for the underlying storage and preventing allocation. If such a backing store is used it would be best to ensure it is a prime number size to mitigate hash collisions.
bool ccc_fhm_occupied | ( | ccc_fhmap_entry const * | e | ) |
Returns the Vacant or Occupied status of the entry.
[in] | e | the entry from a query to the table via function or macro. |
void * ccc_fhm_or_insert | ( | ccc_fhmap_entry const * | e, |
ccc_fhmap_elem * | elem | ||
) |
Inserts the struct with handle elem if the entry is Vacant.
[in] | e | the entry obtained via function or macro call. |
[in] | elem | the handle to the struct to be inserted to a Vacant entry. |
Because this functions takes an entry and inserts if it is Vacant, the only reason NULL shall be returned is when an insertion error will occur, usually due to a resizing memory error. This can happen if the table is not allowed to resize because no allocation function is provided.
ccc_entry ccc_fhm_remove | ( | ccc_flat_hash_map * | h, |
ccc_fhmap_elem * | out_handle | ||
) |
Removes the key value in the map storing the old value, if present, in the struct containing out_handle provided by the user.
[in] | h | the pointer to the flat hash map. |
[out] | out_handle | the handle to the user type wrapping fhash elem. |
Note that this function may write to the struct containing the second parameter and wraps it in an entry to provide information about the old value.
ccc_entry ccc_fhm_remove_entry | ( | ccc_fhmap_entry const * | e | ) |
Remove the entry from the table if Occupied.
[in] | e | a pointer to the table entry. |
size_t ccc_fhm_size | ( | ccc_flat_hash_map const * | h | ) |
Returns the size of the table.
[in] | h | the hash table. |
ccc_entry ccc_fhm_try_insert | ( | ccc_flat_hash_map * | h, |
ccc_fhmap_elem * | key_val_handle | ||
) |
Attempts to insert the key value wrapping key_val_handle.
[in] | h | the pointer to the flat hash map. |
[in] | key_val_handle | the handle to the user type wrapping fhash elem. |
void * ccc_fhm_unwrap | ( | ccc_fhmap_entry const * | e | ) |
Unwraps the provided entry to obtain a view into the table element.
[in] | e | the entry from a query to the table via function or macro. |
bool ccc_fhm_validate | ( | ccc_flat_hash_map const * | h | ) |
Validation of invariants for the hash table.
[in] | h | the table to validate. |