LCOV - code coverage report
Current view: top level - aws-c-common/include/aws/common - hash_table.h (source / functions) Hit Total Coverage
Test: all_fuzz.info Lines: 0 2 0.0 %
Date: 2021-04-23 16:28:21 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef AWS_COMMON_HASH_TABLE_H
       2             : #define AWS_COMMON_HASH_TABLE_H
       3             : 
       4             : /**
       5             :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       6             :  * SPDX-License-Identifier: Apache-2.0.
       7             :  */
       8             : 
       9             : #include <aws/common/common.h>
      10             : 
      11             : #include <stddef.h>
      12             : 
      13           0 : #define AWS_COMMON_HASH_TABLE_ITER_CONTINUE (1 << 0)
      14           0 : #define AWS_COMMON_HASH_TABLE_ITER_DELETE (1 << 1)
      15             : 
      16             : /**
      17             :  * Hash table data structure. This module provides an automatically resizing
      18             :  * hash table implementation for general purpose use. The hash table stores a
      19             :  * mapping between void * keys and values; it is expected that in most cases,
      20             :  * these will point to a structure elsewhere in the heap, instead of inlining a
      21             :  * key or value into the hash table element itself.
      22             :  *
      23             :  * Currently, this hash table implements a variant of robin hood hashing, but
      24             :  * we do not guarantee that this won't change in the future.
      25             :  *
      26             :  * Associated with each hash function are four callbacks:
      27             :  *
      28             :  *   hash_fn - A hash function from the keys to a uint64_t. It is critical that
      29             :  *      the hash function for a key does not change while the key is in the hash
      30             :  *      table; violating this results in undefined behavior. Collisions are
      31             :  *      tolerated, though naturally with reduced performance.
      32             :  *
      33             :  *   equals_fn - An equality comparison function. This function must be
      34             :  *      reflexive and consistent with hash_fn.
      35             :  *
      36             :  *   destroy_key_fn, destroy_value_fn - Optional callbacks invoked when the
      37             :  *      table is cleared or cleaned up and at the caller's option when an element
      38             :  *      is removed from the table. Either or both may be set to NULL, which
      39             :  *      has the same effect as a no-op destroy function.
      40             :  *
      41             :  * This datastructure can be safely moved between threads, subject to the
      42             :  * requirements of the underlying allocator. It is also safe to invoke
      43             :  * non-mutating operations on the hash table from multiple threads. A suitable
      44             :  * memory barrier must be used when transitioning from single-threaded mutating
      45             :  * usage to multithreaded usage.
      46             :  */
      47             : struct hash_table_state; /* Opaque pointer */
      48             : struct aws_hash_table {
      49             :     struct hash_table_state *p_impl;
      50             : };
      51             : 
      52             : /**
      53             :  * Represents an element in the hash table. Various operations on the hash
      54             :  * table may provide pointers to elements stored within the hash table;
      55             :  * generally, calling code may alter value, but must not alter key (or any
      56             :  * information used to compute key's hash code).
      57             :  *
      58             :  * Pointers to elements within the hash are invalidated whenever an operation
      59             :  * which may change the number of elements in the hash is invoked (i.e. put,
      60             :  * delete, clear, and clean_up), regardless of whether the number of elements
      61             :  * actually changes.
      62             :  */
      63             : struct aws_hash_element {
      64             :     const void *key;
      65             :     void *value;
      66             : };
      67             : 
      68             : enum aws_hash_iter_status {
      69             :     AWS_HASH_ITER_STATUS_DONE,
      70             :     AWS_HASH_ITER_STATUS_DELETE_CALLED,
      71             :     AWS_HASH_ITER_STATUS_READY_FOR_USE,
      72             : };
      73             : 
      74             : struct aws_hash_iter {
      75             :     const struct aws_hash_table *map;
      76             :     struct aws_hash_element element;
      77             :     size_t slot;
      78             :     size_t limit;
      79             :     enum aws_hash_iter_status status;
      80             :     /*
      81             :      * Reserving extra fields for binary compatibility with future expansion of
      82             :      * iterator in case hash table implementation changes.
      83             :      */
      84             :     int unused_0;
      85             :     void *unused_1;
      86             :     void *unused_2;
      87             : };
      88             : 
      89             : /**
      90             :  * Prototype for a key hashing function pointer.
      91             :  */
      92             : typedef uint64_t(aws_hash_fn)(const void *key);
      93             : 
      94             : /**
      95             :  * Prototype for a hash table equality check function pointer.
      96             :  *
      97             :  * This type is usually used for a function that compares two hash table
      98             :  * keys, but note that the same type is used for a function that compares
      99             :  * two hash table values in aws_hash_table_eq.
     100             :  *
     101             :  * Equality functions used in a hash table must be reflexive (i.e., a == b if
     102             :  * and only if b == a), and must be consistent with the hash function in use.
     103             :  */
     104             : typedef bool(aws_hash_callback_eq_fn)(const void *a, const void *b);
     105             : 
     106             : /**
     107             :  * Prototype for a hash table key or value destructor function pointer.
     108             :  *
     109             :  * This function is used to destroy elements in the hash table when the
     110             :  * table is cleared or cleaned up.
     111             :  *
     112             :  * Note that functions which remove individual elements from the hash
     113             :  * table provide options of whether or not to invoke the destructors
     114             :  * on the key and value of a removed element.
     115             :  */
     116             : typedef void(aws_hash_callback_destroy_fn)(void *key_or_value);
     117             : 
     118             : AWS_EXTERN_C_BEGIN
     119             : 
     120             : /**
     121             :  * Initializes a hash map with initial capacity for 'size' elements
     122             :  * without resizing. Uses hash_fn to compute the hash of each element.
     123             :  * equals_fn to compute equality of two keys.  Whenever an element is
     124             :  * removed without being returned, destroy_key_fn is run on the pointer
     125             :  * to the key and destroy_value_fn is run on the pointer to the value.
     126             :  * Either or both may be NULL if a callback is not desired in this case.
     127             :  */
     128             : AWS_COMMON_API
     129             : int aws_hash_table_init(
     130             :     struct aws_hash_table *map,
     131             :     struct aws_allocator *alloc,
     132             :     size_t size,
     133             :     aws_hash_fn *hash_fn,
     134             :     aws_hash_callback_eq_fn *equals_fn,
     135             :     aws_hash_callback_destroy_fn *destroy_key_fn,
     136             :     aws_hash_callback_destroy_fn *destroy_value_fn);
     137             : 
     138             : /**
     139             :  * Deletes every element from map and frees all associated memory.
     140             :  * destroy_fn will be called for each element.  aws_hash_table_init
     141             :  * must be called before reusing the hash table.
     142             :  *
     143             :  * This method is idempotent.
     144             :  */
     145             : AWS_COMMON_API
     146             : void aws_hash_table_clean_up(struct aws_hash_table *map);
     147             : 
     148             : /**
     149             :  * Safely swaps two hash tables. Note that we swap the entirety of the hash
     150             :  * table, including which allocator is associated.
     151             :  *
     152             :  * Neither hash table is required to be initialized; if one or both is
     153             :  * uninitialized, then the uninitialized state is also swapped.
     154             :  */
     155             : AWS_COMMON_API
     156             : void aws_hash_table_swap(struct aws_hash_table *AWS_RESTRICT a, struct aws_hash_table *AWS_RESTRICT b);
     157             : 
     158             : /**
     159             :  * Moves the hash table in 'from' to 'to'. After this move, 'from' will
     160             :  * be identical to the state of the original 'to' hash table, and 'to'
     161             :  * will be in the same state as if it had been passed to aws_hash_table_clean_up
     162             :  * (that is, it will have no memory allocated, and it will be safe to
     163             :  * either discard it or call aws_hash_table_clean_up again).
     164             :  *
     165             :  * Note that 'to' will not be cleaned up. You should make sure that 'to'
     166             :  * is either uninitialized or cleaned up before moving a hashtable into
     167             :  * it.
     168             :  */
     169             : AWS_COMMON_API
     170             : void aws_hash_table_move(struct aws_hash_table *AWS_RESTRICT to, struct aws_hash_table *AWS_RESTRICT from);
     171             : 
     172             : /**
     173             :  * Returns the current number of entries in the table.
     174             :  */
     175             : AWS_COMMON_API
     176             : size_t aws_hash_table_get_entry_count(const struct aws_hash_table *map);
     177             : 
     178             : /**
     179             :  * Returns an iterator to be used for iterating through a hash table.
     180             :  * Iterator will already point to the first element of the table it finds,
     181             :  * which can be accessed as iter.element.
     182             :  *
     183             :  * This function cannot fail, but if there are no elements in the table,
     184             :  * the returned iterator will return true for aws_hash_iter_done(&iter).
     185             :  */
     186             : AWS_COMMON_API
     187             : struct aws_hash_iter aws_hash_iter_begin(const struct aws_hash_table *map);
     188             : 
     189             : /**
     190             :  * Returns true if iterator is done iterating through table, false otherwise.
     191             :  * If this is true, the iterator will not include an element of the table.
     192             :  */
     193             : AWS_COMMON_API
     194             : bool aws_hash_iter_done(const struct aws_hash_iter *iter);
     195             : 
     196             : /**
     197             :  * Updates iterator so that it points to next element of hash table.
     198             :  *
     199             :  * This and the two previous functions are designed to be used together with
     200             :  * the following idiom:
     201             :  *
     202             :  * for (struct aws_hash_iter iter = aws_hash_iter_begin(&map);
     203             :  *      !aws_hash_iter_done(&iter); aws_hash_iter_next(&iter)) {
     204             :  *     const key_type key = *(const key_type *)iter.element.key;
     205             :  *     value_type value = *(value_type *)iter.element.value;
     206             :  *     // etc.
     207             :  * }
     208             :  *
     209             :  * Note that calling this on an iter which is "done" is idempotent:
     210             :  * i.e. it will return another iter which is "done".
     211             :  */
     212             : AWS_COMMON_API
     213             : void aws_hash_iter_next(struct aws_hash_iter *iter);
     214             : 
     215             : /**
     216             :  * Deletes the element currently pointed-to by the hash iterator.
     217             :  * After calling this method, the element member of the iterator
     218             :  * should not be accessed until the next call to aws_hash_iter_next.
     219             :  *
     220             :  * @param destroy_contents If true, the destructors for the key and value
     221             :  *  will be called.
     222             :  */
     223             : AWS_COMMON_API
     224             : void aws_hash_iter_delete(struct aws_hash_iter *iter, bool destroy_contents);
     225             : 
     226             : /**
     227             :  * Attempts to locate an element at key.  If the element is found, a
     228             :  * pointer to the value is placed in *p_elem; if it is not found,
     229             :  * *pElem is set to NULL. Either way, AWS_OP_SUCCESS is returned.
     230             :  *
     231             :  * This method does not change the state of the hash table. Therefore, it
     232             :  * is safe to call _find from multiple threads on the same hash table,
     233             :  * provided no mutating operations happen in parallel.
     234             :  *
     235             :  * Calling code may update the value in the hash table by modifying **pElem
     236             :  * after a successful find. However, this pointer is not guaranteed to
     237             :  * remain usable after a subsequent call to _put, _delete, _clear, or
     238             :  * _clean_up.
     239             :  */
     240             : 
     241             : AWS_COMMON_API
     242             : int aws_hash_table_find(const struct aws_hash_table *map, const void *key, struct aws_hash_element **p_elem);
     243             : 
     244             : /**
     245             :  * Attempts to locate an element at key. If no such element was found,
     246             :  * creates a new element, with value initialized to NULL. In either case, a
     247             :  * pointer to the element is placed in *p_elem.
     248             :  *
     249             :  * If was_created is non-NULL, *was_created is set to 0 if an existing
     250             :  * element was found, or 1 is a new element was created.
     251             :  *
     252             :  * Returns AWS_OP_SUCCESS if an item was found or created.
     253             :  * Raises AWS_ERROR_OOM if hash table expansion was required and memory
     254             :  * allocation failed.
     255             :  */
     256             : AWS_COMMON_API
     257             : int aws_hash_table_create(
     258             :     struct aws_hash_table *map,
     259             :     const void *key,
     260             :     struct aws_hash_element **p_elem,
     261             :     int *was_created);
     262             : 
     263             : /**
     264             :  * Inserts a new element at key, with the given value. If another element
     265             :  * exists at that key, the old element will be overwritten; both old key and
     266             :  * value objects will be destroyed.
     267             :  *
     268             :  * If was_created is non-NULL, *was_created is set to 0 if an existing
     269             :  * element was found, or 1 is a new element was created.
     270             :  *
     271             :  * Returns AWS_OP_SUCCESS if an item was found or created.
     272             :  * Raises AWS_ERROR_OOM if hash table expansion was required and memory
     273             :  */
     274             : AWS_COMMON_API
     275             : int aws_hash_table_put(struct aws_hash_table *map, const void *key, void *value, int *was_created);
     276             : 
     277             : /**
     278             :  * Removes element at key. Always returns AWS_OP_SUCCESS.
     279             :  *
     280             :  * If pValue is non-NULL, the existing value (if any) is moved into
     281             :  * (*value) before removing from the table, and destroy_fn is _not_
     282             :  * invoked. If pValue is NULL, then (if the element existed) destroy_fn
     283             :  * will be invoked on the element being removed.
     284             :  *
     285             :  * If was_present is non-NULL, it is set to 0 if the element was
     286             :  * not present, or 1 if it was present (and is now removed).
     287             :  */
     288             : AWS_COMMON_API
     289             : int aws_hash_table_remove(
     290             :     struct aws_hash_table *map,
     291             :     const void *key,
     292             :     struct aws_hash_element *p_value,
     293             :     int *was_present);
     294             : 
     295             : /**
     296             :  * Removes element already known (typically by find()).
     297             :  *
     298             :  * p_value should point to a valid element returned by create() or find().
     299             :  *
     300             :  * NOTE: DO NOT call this method from inside of a aws_hash_table_foreach callback, return
     301             :  * AWS_COMMON_HASH_TABLE_ITER_DELETE instead.
     302             :  */
     303             : AWS_COMMON_API
     304             : int aws_hash_table_remove_element(struct aws_hash_table *map, struct aws_hash_element *p_value);
     305             : 
     306             : /**
     307             :  * Iterates through every element in the map and invokes the callback on
     308             :  * that item. Iteration is performed in an arbitrary, implementation-defined
     309             :  * order, and is not guaranteed to be consistent across invocations.
     310             :  *
     311             :  * The callback may change the value associated with the key by overwriting
     312             :  * the value pointed-to by value. In this case, the on_element_removed
     313             :  * callback will not be invoked, unless the callback invokes
     314             :  * AWS_COMMON_HASH_TABLE_ITER_DELETE (in which case the on_element_removed
     315             :  * is given the updated value).
     316             :  *
     317             :  * The callback must return a bitmask of zero or more of the following values
     318             :  * ORed together:
     319             :  *
     320             :  * # AWS_COMMON_HASH_TABLE_ITER_CONTINUE - Continues iteration to the next
     321             :  *     element (if not set, iteration stops)
     322             :  * # AWS_COMMON_HASH_TABLE_ITER_DELETE   - Deletes the current value and
     323             :  *     continues iteration.  destroy_fn will NOT be invoked.
     324             :  *
     325             :  * Invoking any method which may change the contents of the hashtable
     326             :  * during iteration results in undefined behavior. However, you may safely
     327             :  * invoke non-mutating operations during an iteration.
     328             :  *
     329             :  * This operation is mutating only if AWS_COMMON_HASH_TABLE_ITER_DELETE
     330             :  * is returned at some point during iteration. Otherwise, it is non-mutating
     331             :  * and is safe to invoke in parallel with other non-mutating operations.
     332             :  */
     333             : 
     334             : AWS_COMMON_API
     335             : int aws_hash_table_foreach(
     336             :     struct aws_hash_table *map,
     337             :     int (*callback)(void *context, struct aws_hash_element *p_element),
     338             :     void *context);
     339             : 
     340             : /**
     341             :  * Compares two hash tables for equality. Both hash tables must have equivalent
     342             :  * key comparators; values will be compared using the comparator passed into this
     343             :  * function. The key hash function does not need to be equivalent between the
     344             :  * two hash tables.
     345             :  */
     346             : AWS_COMMON_API
     347             : bool aws_hash_table_eq(
     348             :     const struct aws_hash_table *a,
     349             :     const struct aws_hash_table *b,
     350             :     aws_hash_callback_eq_fn *value_eq);
     351             : 
     352             : /**
     353             :  * Removes every element from the hash map. destroy_fn will be called for
     354             :  * each element.
     355             :  */
     356             : AWS_COMMON_API
     357             : void aws_hash_table_clear(struct aws_hash_table *map);
     358             : 
     359             : /**
     360             :  * Convenience hash function for NULL-terminated C-strings
     361             :  */
     362             : AWS_COMMON_API
     363             : uint64_t aws_hash_c_string(const void *item);
     364             : 
     365             : /**
     366             :  * Convenience hash function for struct aws_strings.
     367             :  * Hash is same as used on the string bytes by aws_hash_c_string.
     368             :  */
     369             : AWS_COMMON_API
     370             : uint64_t aws_hash_string(const void *item);
     371             : 
     372             : /**
     373             :  * Convenience hash function for struct aws_byte_cursor.
     374             :  * Hash is same as used on the string bytes by aws_hash_c_string.
     375             :  */
     376             : AWS_COMMON_API
     377             : uint64_t aws_hash_byte_cursor_ptr(const void *item);
     378             : 
     379             : /**
     380             :  * Convenience hash function which hashes the pointer value directly,
     381             :  * without dereferencing.  This can be used in cases where pointer identity
     382             :  * is desired, or where a uintptr_t is encoded into a const void *.
     383             :  */
     384             : AWS_COMMON_API
     385             : uint64_t aws_hash_ptr(const void *item);
     386             : 
     387             : AWS_COMMON_API
     388             : uint64_t aws_hash_combine(uint64_t item1, uint64_t item2);
     389             : 
     390             : /**
     391             :  * Convenience eq callback for NULL-terminated C-strings
     392             :  */
     393             : AWS_COMMON_API
     394             : bool aws_hash_callback_c_str_eq(const void *a, const void *b);
     395             : 
     396             : /**
     397             :  * Convenience eq callback for AWS strings
     398             :  */
     399             : AWS_COMMON_API
     400             : bool aws_hash_callback_string_eq(const void *a, const void *b);
     401             : 
     402             : /**
     403             :  * Convenience destroy callback for AWS strings
     404             :  */
     405             : AWS_COMMON_API
     406             : void aws_hash_callback_string_destroy(void *a);
     407             : 
     408             : /**
     409             :  * Equality function which compares pointer equality.
     410             :  */
     411             : AWS_COMMON_API
     412             : bool aws_ptr_eq(const void *a, const void *b);
     413             : 
     414             : /**
     415             :  * Best-effort check of hash_table_state data-structure invariants
     416             :  */
     417             : AWS_COMMON_API
     418             : bool aws_hash_table_is_valid(const struct aws_hash_table *map);
     419             : 
     420             : /**
     421             :  * Given a pointer to a hash_iter, checks that it is well-formed, with all data-structure invariants.
     422             :  */
     423             : AWS_COMMON_API
     424             : bool aws_hash_iter_is_valid(const struct aws_hash_iter *iter);
     425             : 
     426             : AWS_EXTERN_C_END
     427             : 
     428             : #endif /* AWS_COMMON_HASH_TABLE_H */

Generated by: LCOV version 1.13