#pragma once #include #include struct table_t; /** "INVALID_KEY" may be used internally to mark non-existing items */ #define INVALID_KEY INT_MIN /** "INVALID_VAL" shall be returned if no value was associated with the key */ #define INVALID_VAL INT_MIN /** "INVALID_ARGUMENTS" shall be returned if provided arguments are invalid */ #define INVALID_ARGUMENTS (INVALID_VAL + 1) /** "OUT_OF_MEMORY" shall be returned if the system ran out of memory */ #define OUT_OF_MEMORY (INVALID_VAL + 2) /** Creates a new hash table. * Bucket size (number of items in bucket) stays fixed. * The map shall initially have the number of buckets as provided. * @returns * INVALID_ARGUMENTS if table is NULL or numberOfBuckets is 0 or bucketSize is 0, or * OUT_OF_MEMORY if dynamic memory allocation failed, or * EXIT_SUCCESS. */ int table_init(struct table_t **table, size_t numberOfBuckets, size_t bucketSize); /** Adds or replaces "value" under the "key" to the "table", and if the pointer * "oldValue" is not null, the old value is written to "*oldValue" (if there * was no value associated with the key, INVALID_VAL must be written instead). * If needed, doubles the bucket count to make space for the new element. * @returns * INVALID_ARGUMENTS if table is NULL or key is "INVALID_KEY" or value is "INVALID_VAL", or * OUT_OF_MEMORY if dynamic memory allocation failed, or * EXIT_SUCCESS. */ int table_insert(struct table_t *table, int key, int value, int *oldValue); /** @returns * INVALID_ARGUMENTS if table is NULL or key is "INVALID_KEY", or * INVALID_VAL if the provided key does not exist in the table, or * the value associated with "key" in the "table" */ int table_lookup(struct table_t *table, int key); /** Acts identical to "table_lookup", but additionally erases the key from the * table */ int table_deleteKey(struct table_t *table, int key); /** If the table contains given key, "table_awaitAndDelete" acts identical to * "table_delete", else "table_awaitAndDelete" waits until the given key is * added (by a concurrent thread) to the table and then acts identical to * "table_delete". */ int table_awaitAndDelete(struct table_t *table, int key); /** Deallocates all memory associated with the table. * @returns * INVALID_ARGUMENTS if table is NULL, or * EXIT_SUCCESS. */ int table_destroy(struct table_t *table); struct table_iterator_t; /** Creates a new "table_iterator_t" object and returns it to caller. * The caller must then execute "table_next" until it returns "TABLE_END". * Please read the description of "table_next" for more information. * @returns * NULL if table is NULL, or * address of the new iterator object. */ struct table_iterator_t *table_begin(struct table_t *table); /** "TABLE_END" is returned by "table_next" if all items were iterated over */ #define TABLE_END -1 /** Checks if there is an item that was not yet visited. * * If there is such item, this function sets "*key" to the key and "*value" * to the pointer to the item and returns EXIT_SUCCESS. Note that the value * can be changed via the pointer until subsequent call to "table_next". * * If there is no such item, this function returns "TABLE_END" and destroys * the iterator, freeing all resources associated with it. * * * If a "table_deleteKey" or "table_awaitAndDelete" is called concurrently * (i.e., between the "table_begin" and the last "table_next"), the deleted * key may or may not be iterated over. * * If a "table_insert" is called concurrently (i.e., between the "table_begin" * and the last "table_next"), the added key may or may not be iterated over, * but no item can be iterated over multiple times. * * @returns * INVALID_ARGUMENTS if table_next is NULL, or * TABLE_END if all elements were returned by previous calls to table_next, or * EXIT_SUCCESS if key and *value point to the next item. */ int table_next(struct table_iterator_t *iterator, int *key, int **value);