dox/API_HASHMAP.md
79616338
 # `mulle_concurrent_hashmap`
 
 `mulle_concurrent_hashmap` is a mutable map of pointers, indexed by a hash.
f8b0390e
 What is it good for ?  It's good for a table, that needs to be accessed quickly
 and often by multiple threads. Rule of thumb, if your process is spending a lot
 of time locking and unlocking a central hashtable, you
 want `mulle_concurrent_hashmap`.
 
 Such a hashmap is extremely volatile when shared with multiple threads, that are
 inserting and removing entries. For example, when you get the number of elements
 of a such a hashmap it is akin to a fleeting glimpse of a distant past.
79616338
 
 The following operations should be executed in single-threaded fashion:
 
c81618a8
 * `mulle_concurrent_hashmap_init`
 * `mulle_concurrent_hashmap_done`
79616338
 
 The following operations are fine in multi-threaded environments:
 
c81618a8
 * `mulle_concurrent_hashmap_insert`
 * `mulle_concurrent_hashmap_remove`
 * `mulle_concurrent_hashmap_lookup`
79616338
 
c81618a8
 The following operations work in multi-threaded environments, but should be
 approached with caution:
79616338
 
 * `mulle_concurrent_hashmap_enumerate`
 * `mulle_concurrent_hashmap_lookup_any`
 * `mulle_concurrent_hashmap_count`
f8b0390e
 * `mulle_concurrent_hashmap_get_size`
79616338
 
c81618a8
 
79616338
 ## single-threaded
 
 
c81618a8
 ### `mulle_concurrent_hashmap_init`
79616338
 
 ```
c81618a8
 int   mulle_concurrent_hashmap_init( struct mulle_concurrent_hashmap *map,
                                      unsigned int size,
                                      struct mulle_allocator *allocator)
79616338
 ```
 
 Initialize `map`, with a starting `size` of elements. `allocator` will be
 used to allocate and free memory during the lifetime of `map`.  You can pass in
 for `allocator` to use the default. Call this in single-threaded fashion.
 
c81618a8
 Return Values:
f8b0390e
 
 *   0      : OK
 *   EINVAL : invalid argument
 *   ENOMEM : out of memory
c81618a8
 
79616338
 
c81618a8
 ### `void  mulle_concurrent_hashmap_done`
79616338
 
 ```
c81618a8
 void  mulle_concurrent_hashmap_done( struct mulle_concurrent_hashmap *map)
79616338
 ```
 
 This will free all allocated resources `map`. It will not **free** `map` itself
 though. `map` must be a valid pointer. Call this in single-threaded fashion.
 
 
 ## multi-threaded
 
 
c81618a8
 ### `mulle_concurrent_hashmap_insert`
79616338
 
 ```
c81618a8
 int  mulle_concurrent_hashmap_insert( struct mulle_concurrent_hashmap *map,
                                       intptr_t hash,
                                       void *value)
79616338
 ```
 
 Insert a `hash`, `value` pair.
 `hash` must not be zero. It should be a unique integer key, suitably treated to
 be a good hash value. Here is an example of an avalance function for simple
 integer keys (1-...)
 
 ```
 static inline uint64_t   mulle_hash_avalanche64(uint64_t h)
 {
    h ^= h >> 33;
    h *= 0xff51afd7ed558ccd;
    h ^= h >> 33;
    h *= 0xc4ceb9fe1a85ec53;
    h ^= h >> 33;
    return h;
 }
 ```
 
75aba9d2
 `value` can be any `void *` except `NULL` or `(void *) INTPTR_MIN`.  It will
79616338
 not get dereferenced by the hashmap.
 
 
 Return Values:
f8b0390e
 
 *   0      : OK
 *   EEXIST : duplicate
 *   ENOMEM : out of memory
79616338
 
 
c81618a8
 ### `mulle_concurrent_hashmap_remove`
79616338
 
 ```
c81618a8
 int  mulle_concurrent_hashmap_remove( struct mulle_concurrent_hashmap *map,
75aba9d2
                                       intptr_t hash,
                                       void *value)
79616338
 ```
 
 Remove a `hash`, `value` pair. Read the description of
c81618a8
 `mulle_concurrent_hashmap_insert` for information about restrictions
79616338
 pertaining to both.
 
 Return Values:
    0      : OK
    ENOENT : not found
    ENOMEM : out of memory
 
 
c81618a8
 ### `mulle_concurrent_hashmap_lookup`
79616338
 
 ```
c81618a8
 void   *mulle_concurrent_hashmap_lookup( struct mulle_concurrent_hashmap *map,
79616338
                                           intptr_t hash)
 ```
 
 Looks up a value by its hash.
 
 Return Values:
f8b0390e
 
 *   NULL  : not found
 *   otherwise the value for this hash
79616338
 
75aba9d2
 
 ### `mulle_concurrent_hashmap_enumerate`
 
 ```
 struct mulle_concurrent_hashmapenumerator  mulle_concurrent_hashmap_enumerate( struct mulle_concurrent_hashmap *map)
 ```
 
 Enumerate a hashtable. See `mulle_concurrent_hashmapenumerator_next` for more details.
 It returns a `mulle_concurrent_hashmapenumerator`. This enumerator should not be jointly accessed by multiple threads.
 
79616338
 ---
 
c81618a8
 
 ### `mulle_concurrent_hashmap_get_size`
 
 ```
f8b0390e
 unsigned int   mulle_concurrent_hashmap_get_size( struct mulle_concurrent_hashmap *map);
c81618a8
 ```
 
f8b0390e
 This gives you the current capacity of hash/value entries of `map`. The returned
 number maybe not as meaningful as one might think, if the map is accessed in multi-threaded fashion.
c81618a8
 
 
79616338
 # `mulle_concurrent_hashmapenumerator`
 
75aba9d2
 The following two functions operate on an enumerator over the possibly multi-threaded hashmap, the enumerator itself should not be accessed by multiple threads.
 
 * `mulle_concurrent_hashmapenumerator_next`
 * `mulle_concurrent_hashmapenumerator_done`
 
 
 ### `mulle_concurrent_hashmapenumerator_next`
 
79616338
 ```
75aba9d2
 int  mulle_concurrent_hashmapenumerator_next( struct mulle_concurrent_hashmapenumerator *rover,
                                                intptr_t *hash,
                                                void **value)
79616338
 ```
 
75aba9d2
 Get the next `hash`, `value` pair from the enumerator. This works reliably if `map` is accessed in single-threaded fashion, which it probably will NOT be. In multi-threaded
79616338
 environments, the enumeration may be interrupted by mutations of the hashtable
 by other threads. The enumerator itself should not be shared with other threads.
 
 Here is a simple usage example:
 
 
 ```
    struct mulle_concurrent_hashmap             *map;
    struct mulle_concurrent_hashmapenumerator   rover;
    intptr_t                                    hash;
    void                                        *value;
f8b0390e
    int                                         rval;
79616338
 
f8b0390e
 retry:
79616338
    rover = mulle_concurrent_hashmap_enumerate( map);
f8b0390e
    while( (rval = mulle_concurrent_hashmapenumerator_next( &rover, &hash, &value) == 1))
79616338
    {
       printf( "%ld %p\n", hash, value);
    }
c81618a8
    mulle_concurrent_hashmapenumerator_done( &rover);
f8b0390e
 
75aba9d2
    if( rval == EBUSY) // interrupted!
       goto retry;     // restart from the beginning will duplicate some
79616338
 ```
 
 Return Values:
f8b0390e
 
 *   1          : OK
 *   0          : nothing left
 *   ECANCELLED : hashtable was mutated
 *   ENOMEM     : out of memory
79616338
 
 
c81618a8
 ### `mulle_concurrent_hashmapenumerator_done`
79616338
 
 ```
c81618a8
 void  mulle_concurrent_hashmapenumerator_done( struct mulle_concurrent_hashmapenumerator *rover)
79616338
 ```
 
 It's a mere conventional function. It may be left out.
 
 
 ### `mulle_concurrent_hashmap_count`
 
 ```
 unsigned int   mulle_concurrent_hashmap_count( struct mulle_concurrent_hashmap *map);
 ```
 
c81618a8
 This gives you the current number of hash/value entries of `map`. It is
 implemented as an iterator loop, that counts the number of values.
 The returned number may be close to meaningless, when the map is accessed in
 multi-threaded fashion.
79616338
 
 
 ### `mulle_concurrent_hashmap_lookup_any` - get a value from the hashmap
 
 ```
 void  *mulle_concurrent_hashmap_lookup_any( struct mulle_concurrent_hashmap *map);
 ```
 
 This will return a value from the map. It is implemented as an iterator loop,
 that returns the first value. It returns NULL if `map` contains no entries or
 is NULL.