ID Map
Internally, NNG uses a map of numeric identifiers to data structures. This feature is also exposed for application use, as a “supplemental” feature.
When using these functions, it is necessary to add the #include <nng/supplemental/util/idhash.h>
include file to list of includes.
ID Map Structure
#include <nng/nng.h>
#include <nng/supplemental/util/idhash.h>
typedef struct nng_id_map_s nng_id_map;
The ID map structure, nng_id_map
provides a table of identifiers mapping
to user-supplied pointers (which must not be NULL
). The identifiers can be
thought of as indices into the table, with the pointers providing the reference
for the user supplied data.
The values of identifiers can be supplied by the user, or can be allocated automatically
by nng_id_map
from a predefined range. The starting point for allocations
can also be randomly within the range.
The identifiers are 64-bit unsigned integers and can be sparse; the structure will use space efficiently even if identifiers are very far apart. 1
important
The function available for nng_id_map
are not thread-safe.
Callers should use a mutex or similar approach when thread-safety is needed.
Create ID Map
#define NNG_MAP_RANDOM 1
int nng_id_map_alloc(nng_id_map **map_p, uint64_t lo, uint64_t hi, int flags);
The nng_id_map_alloc
function allocates a map without any data in it,
and returns a pointer to it in map_p. When allocating identifiers dynamically,
the values will be chosen from the range defined by lo and hi, inclusive.
The flags argument is a bit mask of flags that can adjust behavior of the map.
The only flag defined at present
is NNG_MAP_RANDOM
, which causes the first identifier allocation to start at a random
point within the range.
This is useful to reduce the odds of different instances of an application using
the same identifiers at the same time.
If both lo and hi are zero, then the values 0
and 0xffffffff
are substituted
in their place, giving a full range of 32-bit identifiers.
This function can return NNG_ENOMEM
if it is unable to allocate resources, otherwise
it returns zero on success.
Destroy Map
void nng_id_map_free(nng_id_map *map);
The nng_id_map_free
function destroys map, releasing any resources associated
with it.
note
The nng_id_map_free
frees the map itself, but will not free memory associated with
any strctures contained within it.
Store a Value
int nng_id_set(nng_id_map *map, uint64_t id, void *value);
The nng_id_map_set
function is used to store the value in the map at
index id.
If another value is already stored at that same location, then it is overwritten with value.
note
The value must not be NULL
.
If the table has to grow to accommodate this value, it may fail if insufficient
memory is available, returning NNG_ENOMEM
. Otherwise it returns zero.
Lookup a Value
void *nng_id_get(nng_id_map *map, uint64_t id);
The nng_id_get
function looks up the entry for id in map, returning the
associated value if present, or NULL
if no such entry exists.
Allocate an ID
int nng_id_alloc(nng_id_map *map, uint64_t *id_p, void *value);
The nng_id_alloc
stores the value in the map, at a newly allocated index,
and returns the index in id_p.
Identifiers are allocated in increasing order, without reusing old identifiers until the largest possible identifier is allocated. After wrapping, only identifiers that are no longer in use will be considered. No effort is made to order the availability of identifiers based on when they were freed.2
As with nng_id_set
, this may need to allocate memory and can thus
fail with NNG_ENOMEM
.
Additionally, if there are no more free identifiers within the range specified
when map was created, then it will return NNG_ENOSPC
.
Otherwise it returns zero, indicating success.
Remove an ID
int nng_id_remove(nng_id_map *map, uint64_t id);
The nng_id_remove
removes the entry at index id from map.
If no such entry exist, it will return NNG_ENOENT
. Otherwise it returns zero.
Iterating IDs
bool nng_id_visit(nng_id_map *map, uint64_t *id_p, void **value_p, uint32_t *cursor);
The nng_id_visit
function is used to iterate over all items in the table.
The caller starts the iteration by setting the cursor to 0 before calling it.
For each call, the associated key and value of the next item will be returned in id_p,
and value_p and the cursor will be updated.
When all items have been iterated, the function returns false
.
The order of items returned is not guaranteed to be sequential.
The caller must not attempt to derive any value of the cursor as it refers to internal table indices.
Entries may be safely removed from map while iterating.
However, if new entries are added to the table while iterating, the result of iteration is undefined; entries may be repeated or omitted during such an iteration.
The caller must not attempt to derive any value of the cursor as it refers to internal table indices.
1: The ID map is capable of storing at most 232 identifiers, even though the identifers may themselves be much larger than this.
2: The concern about possibly reusing a recently released identifier comes into consideration after the range has wrapped. Given a sufficiently large range, this is unlikely to be a concern.