Fri, 23 May 2025 12:44:24 +0200
make test-compile depend on both static and shared
the shared lib is not needed for the tests,
but when run with coverage, gcov will be confused
when outdated line information is available from
a previous shared build
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @file map.h * @brief Interface for map implementations. * @author Mike Becker * @author Olaf Wintermann * @copyright 2-Clause BSD License */ #ifndef UCX_MAP_H #define UCX_MAP_H #include "common.h" #include "collection.h" #include "string.h" #include "hash_key.h" #ifdef __cplusplus extern "C" { #endif /** Type for the UCX map. */ typedef struct cx_map_s CxMap; /** Type for a map entry. */ typedef struct cx_map_entry_s CxMapEntry; /** Type for a map iterator. */ typedef struct cx_map_iterator_s CxMapIterator; /** Type for map class definitions. */ typedef struct cx_map_class_s cx_map_class; /** Structure for the UCX map. */ struct cx_map_s { /** * Base attributes. */ CX_COLLECTION_BASE; /** The map class definition. */ cx_map_class *cl; }; /** * A map entry. */ struct cx_map_entry_s { /** * A pointer to the key. */ const CxHashKey *key; /** * A pointer to the value. */ void *value; }; /** * The type of iterator for a map. */ enum cx_map_iterator_type { /** * Iterates over key/value pairs. */ CX_MAP_ITERATOR_PAIRS, /** * Iterates over keys only. */ CX_MAP_ITERATOR_KEYS, /** * Iterates over values only. */ CX_MAP_ITERATOR_VALUES }; /** * Internal iterator struct - use CxMapIterator. */ struct cx_map_iterator_s { /** * Inherited common data for all iterators. */ CX_ITERATOR_BASE; /** * Handle for the source map. */ union { /** * Access for mutating iterators. */ CxMap *m; /** * Access for normal iterators. */ const CxMap *c; } map; /** * Handle for the current element. * * @attention Depends on the map implementation, do not assume a type (better: do not use!). */ void *elem; /** * Reserved memory for a map entry. * * If a map implementation uses an incompatible layout, the iterator needs something * to point to during iteration which @em is compatible. */ CxMapEntry entry; /** * Field for storing the current slot number. * * (Used internally) */ size_t slot; /** * Counts the elements successfully. * It usually does not denote a stable index within the map as it would be for arrays. */ size_t index; /** * The size of a value stored in this map. */ size_t elem_size; /** * May contain the total number of elements, if known. * Set to @c SIZE_MAX when the total number is unknown during iteration. * * @remark The UCX implementations of #CxMap always know the number of elements they store. */ size_t elem_count; /** * The type of this iterator. */ enum cx_map_iterator_type type; }; /** * The class definition for arbitrary maps. */ struct cx_map_class_s { /** * Deallocates the entire memory. */ void (*deallocate)(struct cx_map_s *map); /** * Removes all elements. */ void (*clear)(struct cx_map_s *map); /** * Add or overwrite an element. */ int (*put)( CxMap *map, CxHashKey key, void *value ); /** * Returns an element. */ void *(*get)( const CxMap *map, CxHashKey key ); /** * Removes an element. * * Implementations SHALL check if @p targetbuf is set and copy the elements * to the buffer without invoking any destructor. * When @p targetbuf is not set, the destructors SHALL be invoked. * * The function SHALL return zero when the @p key was found and * non-zero, otherwise. */ int (*remove)( CxMap *map, CxHashKey key, void *targetbuf ); /** * Creates an iterator for this map. */ CxMapIterator (*iterator)(const CxMap *map, enum cx_map_iterator_type type); }; /** * A shared instance of an empty map. * * Writing to that map is not allowed. * * You can use this is a placeholder for initializing CxMap pointers * for which you do not want to reserve memory right from the beginning. */ cx_attr_export extern CxMap *const cxEmptyMap; /** * Deallocates the memory of the specified map. * * Also calls the content destructor functions for each element, if specified. * * @param map the map to be freed */ cx_attr_export void cxMapFree(CxMap *map); /** * Clears a map by removing all elements. * * Also calls the content destructor functions for each element, if specified. * * @param map the map to be cleared */ cx_attr_nonnull static inline void cxMapClear(CxMap *map) { map->cl->clear(map); } /** * Returns the number of elements in this map. * * @param map the map * @return the number of stored elements */ cx_attr_nonnull static inline size_t cxMapSize(const CxMap *map) { return map->collection.size; } /** * Creates a value iterator for a map. * * When the map is storing pointers, those pointers are returned. * Otherwise, the iterator iterates over pointers to the memory within the map where the * respective elements are stored. * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * * @param map the map to create the iterator for * @return an iterator for the currently stored values */ cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIteratorValues(const CxMap *map) { return map->cl->iterator(map, CX_MAP_ITERATOR_VALUES); } /** * Creates a key iterator for a map. * * The elements of the iterator are keys of type CxHashKey and the pointer returned * during iterator shall be treated as @c const @c CxHashKey* . * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * * @param map the map to create the iterator for * @return an iterator for the currently stored keys */ cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIteratorKeys(const CxMap *map) { return map->cl->iterator(map, CX_MAP_ITERATOR_KEYS); } /** * Creates an iterator for a map. * * The elements of the iterator are key/value pairs of type CxMapEntry and the pointer returned * during iterator shall be treated as @c const @c CxMapEntry* . * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * * @param map the map to create the iterator for * @return an iterator for the currently stored entries * @see cxMapIteratorKeys() * @see cxMapIteratorValues() */ cx_attr_nonnull cx_attr_nodiscard static inline CxMapIterator cxMapIterator(const CxMap *map) { return map->cl->iterator(map, CX_MAP_ITERATOR_PAIRS); } /** * Creates a mutating iterator over the values of a map. * * When the map is storing pointers, those pointers are returned. * Otherwise, the iterator iterates over pointers to the memory within the map where the * respective elements are stored. * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * * @param map the map to create the iterator for * @return an iterator for the currently stored values */ cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIteratorValues(CxMap *map); /** * Creates a mutating iterator over the keys of a map. * * The elements of the iterator are keys of type CxHashKey and the pointer returned * during iterator shall be treated as @c const @c CxHashKey* . * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * * @param map the map to create the iterator for * @return an iterator for the currently stored keys */ cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIteratorKeys(CxMap *map); /** * Creates a mutating iterator for a map. * * The elements of the iterator are key/value pairs of type CxMapEntry and the pointer returned * during iterator shall be treated as @c const @c CxMapEntry* . * * @note An iterator iterates over all elements successively. Therefore, the order * highly depends on the map implementation and may change arbitrarily when the contents change. * * @param map the map to create the iterator for * @return an iterator for the currently stored entries * @see cxMapMutIteratorKeys() * @see cxMapMutIteratorValues() */ cx_attr_nonnull cx_attr_nodiscard cx_attr_export CxMapIterator cxMapMutIterator(CxMap *map); #ifdef __cplusplus } // end the extern "C" block here, because we want to start overloading cx_attr_nonnull static inline int cxMapPut( CxMap *map, CxHashKey const &key, void *value ) { return map->cl->put(map, key, value); } cx_attr_nonnull static inline int cxMapPut( CxMap *map, cxstring const &key, void *value ) { return map->cl->put(map, cx_hash_key_cxstr(key), value); } cx_attr_nonnull static inline int cxMapPut( CxMap *map, cxmutstr const &key, void *value ) { return map->cl->put(map, cx_hash_key_cxstr(key), value); } cx_attr_nonnull cx_attr_cstr_arg(2) static inline int cxMapPut( CxMap *map, const char *key, void *value ) { return map->cl->put(map, cx_hash_key_str(key), value); } cx_attr_nonnull cx_attr_nodiscard static inline void *cxMapGet( const CxMap *map, CxHashKey const &key ) { return map->cl->get(map, key); } cx_attr_nonnull cx_attr_nodiscard static inline void *cxMapGet( const CxMap *map, cxstring const &key ) { return map->cl->get(map, cx_hash_key_cxstr(key)); } cx_attr_nonnull cx_attr_nodiscard static inline void *cxMapGet( const CxMap *map, cxmutstr const &key ) { return map->cl->get(map, cx_hash_key_cxstr(key)); } cx_attr_nonnull cx_attr_nodiscard cx_attr_cstr_arg(2) static inline void *cxMapGet( const CxMap *map, const char *key ) { return map->cl->get(map, cx_hash_key_str(key)); } cx_attr_nonnull static inline int cxMapRemove( CxMap *map, CxHashKey const &key ) { return map->cl->remove(map, key, nullptr); } cx_attr_nonnull static inline int cxMapRemove( CxMap *map, cxstring const &key ) { return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr); } cx_attr_nonnull static inline int cxMapRemove( CxMap *map, cxmutstr const &key ) { return map->cl->remove(map, cx_hash_key_cxstr(key), nullptr); } cx_attr_nonnull cx_attr_cstr_arg(2) static inline int cxMapRemove( CxMap *map, const char *key ) { return map->cl->remove(map, cx_hash_key_str(key), nullptr); } cx_attr_nonnull cx_attr_access_w(3) static inline int cxMapRemoveAndGet( CxMap *map, CxHashKey key, void *targetbuf ) { return map->cl->remove(map, key, targetbuf); } cx_attr_nonnull cx_attr_access_w(3) static inline int cxMapRemoveAndGet( CxMap *map, cxstring key, void *targetbuf ) { return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf); } cx_attr_nonnull cx_attr_access_w(3) static inline int cxMapRemoveAndGet( CxMap *map, cxmutstr key, void *targetbuf ) { return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf); } cx_attr_nonnull cx_attr_access_w(3) cx_attr_cstr_arg(2) static inline int cxMapRemoveAndGet( CxMap *map, const char *key, void *targetbuf ) { return map->cl->remove(map, cx_hash_key_str(key), targetbuf); } #else // __cplusplus /** * @copydoc cxMapPut() */ cx_attr_nonnull static inline int cx_map_put( CxMap *map, CxHashKey key, void *value ) { return map->cl->put(map, key, value); } /** * @copydoc cxMapPut() */ cx_attr_nonnull static inline int cx_map_put_cxstr( CxMap *map, cxstring key, void *value ) { return map->cl->put(map, cx_hash_key_cxstr(key), value); } /** * @copydoc cxMapPut() */ cx_attr_nonnull static inline int cx_map_put_mustr( CxMap *map, cxmutstr key, void *value ) { return map->cl->put(map, cx_hash_key_cxstr(key), value); } /** * @copydoc cxMapPut() */ cx_attr_nonnull cx_attr_cstr_arg(2) static inline int cx_map_put_str( CxMap *map, const char *key, void *value ) { return map->cl->put(map, cx_hash_key_str(key), value); } /** * Puts a key/value-pair into the map. * * A possible existing value will be overwritten. * If destructor functions are specified, they are called for * the overwritten element. * * If this map is storing pointers, the @p value pointer is written * to the map. Otherwise, the memory is copied from @p value with * memcpy(). * * The @p key is always copied. * * @param map (@c CxMap*) the map * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key * @param value (@c void*) the value * @retval zero success * @retval non-zero value on memory allocation failure */ #define cxMapPut(map, key, value) _Generic((key), \ CxHashKey: cx_map_put, \ cxstring: cx_map_put_cxstr, \ cxmutstr: cx_map_put_mustr, \ char*: cx_map_put_str, \ const char*: cx_map_put_str) \ (map, key, value) /** * @copydoc cxMapGet() */ cx_attr_nonnull cx_attr_nodiscard static inline void *cx_map_get( const CxMap *map, CxHashKey key ) { return map->cl->get(map, key); } /** * @copydoc cxMapGet() */ cx_attr_nonnull cx_attr_nodiscard static inline void *cx_map_get_cxstr( const CxMap *map, cxstring key ) { return map->cl->get(map, cx_hash_key_cxstr(key)); } /** * @copydoc cxMapGet() */ cx_attr_nonnull cx_attr_nodiscard static inline void *cx_map_get_mustr( const CxMap *map, cxmutstr key ) { return map->cl->get(map, cx_hash_key_cxstr(key)); } /** * @copydoc cxMapGet() */ cx_attr_nonnull cx_attr_nodiscard cx_attr_cstr_arg(2) static inline void *cx_map_get_str( const CxMap *map, const char *key ) { return map->cl->get(map, cx_hash_key_str(key)); } /** * Retrieves a value by using a key. * * If this map is storing pointers, the stored pointer is returned. * Otherwise, a pointer to the element within the map's memory * is returned (which is valid as long as the element stays in the map). * * @param map (@c CxMap*) the map * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key * @return (@c void*) the value */ #define cxMapGet(map, key) _Generic((key), \ CxHashKey: cx_map_get, \ cxstring: cx_map_get_cxstr, \ cxmutstr: cx_map_get_mustr, \ char*: cx_map_get_str, \ const char*: cx_map_get_str) \ (map, key) /** * @copydoc cxMapRemove() */ cx_attr_nonnull static inline int cx_map_remove( CxMap *map, CxHashKey key ) { return map->cl->remove(map, key, NULL); } /** * @copydoc cxMapRemove() */ cx_attr_nonnull static inline int cx_map_remove_cxstr( CxMap *map, cxstring key ) { return map->cl->remove(map, cx_hash_key_cxstr(key), NULL); } /** * @copydoc cxMapRemove() */ cx_attr_nonnull static inline int cx_map_remove_mustr( CxMap *map, cxmutstr key ) { return map->cl->remove(map, cx_hash_key_cxstr(key), NULL); } /** * @copydoc cxMapRemove() */ cx_attr_nonnull cx_attr_cstr_arg(2) static inline int cx_map_remove_str( CxMap *map, const char *key ) { return map->cl->remove(map, cx_hash_key_str(key), NULL); } /** * Removes a key/value-pair from the map by using the key. * * Always invokes the destructors functions, if any, on the removed element. * * @param map (@c CxMap*) the map * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key * @retval zero success * @retval non-zero the key was not found * * @see cxMapRemoveAndGet() */ #define cxMapRemove(map, key) _Generic((key), \ CxHashKey: cx_map_remove, \ cxstring: cx_map_remove_cxstr, \ cxmutstr: cx_map_remove_mustr, \ char*: cx_map_remove_str, \ const char*: cx_map_remove_str) \ (map, key) /** * @copydoc cxMapRemoveAndGet() */ cx_attr_nonnull cx_attr_access_w(3) static inline int cx_map_remove_and_get( CxMap *map, CxHashKey key, void *targetbuf ) { return map->cl->remove(map, key, targetbuf); } /** * @copydoc cxMapRemoveAndGet() */ cx_attr_nonnull cx_attr_access_w(3) static inline int cx_map_remove_and_get_cxstr( CxMap *map, cxstring key, void *targetbuf ) { return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf); } /** * @copydoc cxMapRemoveAndGet() */ cx_attr_nonnull cx_attr_access_w(3) static inline int cx_map_remove_and_get_mustr( CxMap *map, cxmutstr key, void *targetbuf ) { return map->cl->remove(map, cx_hash_key_cxstr(key), targetbuf); } /** * @copydoc cxMapRemoveAndGet() */ cx_attr_nonnull cx_attr_access_w(3) cx_attr_cstr_arg(2) static inline int cx_map_remove_and_get_str( CxMap *map, const char *key, void *targetbuf ) { return map->cl->remove(map, cx_hash_key_str(key), targetbuf); } /** * Removes a key/value-pair from the map by using the key. * * This function will copy the contents of the removed element * to the target buffer, which must be guaranteed to be large enough * to hold the element (the map's element size). * The destructor functions, if any, will @em not be called. * * If this map is storing pointers, the element is the pointer itself * and not the object it points to. * * @param map (@c CxMap*) the map * @param key (@c CxHashKey, @c char*, @c cxstring, or @c cxmutstr) the key * @param targetbuf (@c void*) the buffer where the element shall be copied to * @retval zero success * @retval non-zero the key was not found * * @see cxMapRemove() */ #define cxMapRemoveAndGet(map, key, targetbuf) _Generic((key), \ CxHashKey: cx_map_remove_and_get, \ cxstring: cx_map_remove_and_get_cxstr, \ cxmutstr: cx_map_remove_and_get_mustr, \ char*: cx_map_remove_and_get_str, \ const char*: cx_map_remove_and_get_str) \ (map, key, targetbuf) #endif // __cplusplus #endif // UCX_MAP_H