Fri, 21 Apr 2023 19:50:43 +0200
bring a generic interface to CxMap
src/cx/hash_map.h | file | annotate | diff | comparison | revisions | |
src/cx/map.h | file | annotate | diff | comparison | revisions | |
src/hash_map.c | file | annotate | diff | comparison | revisions | |
tests/CMakeLists.txt | file | annotate | diff | comparison | revisions | |
tests/test_map.cpp | file | annotate | diff | comparison | revisions | |
tests/test_map_generics.c | file | annotate | diff | comparison | revisions | |
tests/test_map_generics.h | file | annotate | diff | comparison | revisions |
--- a/src/cx/hash_map.h Fri Apr 21 18:38:18 2023 +0200 +++ b/src/cx/hash_map.h Fri Apr 21 19:50:43 2023 +0200 @@ -84,7 +84,7 @@ */ __attribute__((__nonnull__, __warn_unused_result__)) CxMap *cxHashMapCreate( - CxAllocator *allocator, + CxAllocator const *allocator, size_t itemsize, size_t buckets );
--- a/src/cx/map.h Fri Apr 21 18:38:18 2023 +0200 +++ b/src/cx/map.h Fri Apr 21 19:50:43 2023 +0200 @@ -39,6 +39,7 @@ #include "common.h" #include "collection.h" +#include "string.h" #include "hash_key.h" #ifdef __cplusplus @@ -211,108 +212,6 @@ map->cl->clear(map); } -/** - * Puts a key/value-pair into the map. - * - * @param map the map - * @param key the key - * @param value the value - * @return 0 on success, non-zero value on failure - */ -__attribute__((__nonnull__)) -static inline int cxMapPut( - CxMap *map, - CxHashKey key, - void *value -) { - return map->cl->put(map, key, value); -} - -/** - * Retrieves a value by using a key. - * - * @param map the map - * @param key the key - * @return the value - */ -__attribute__((__nonnull__, __warn_unused_result__)) -static inline void *cxMapGet( - CxMap const *map, - CxHashKey key -) { - return map->cl->get(map, key); -} - -/** - * Removes a key/value-pair from the map by using the key. - * - * Always invokes the destructor function, if any, on the removed element. - * If this map is storing pointers and you just want to retrieve the pointer - * without invoking the destructor, use cxMapRemoveAndGet(). - * If you just want to detach the element from the map without invoking the - * destructor or returning the element, use cxMapDetach(). - * - * @param map the map - * @param key the key - * @see cxMapRemoveAndGet() - * @see cxMapDetach() - */ -__attribute__((__nonnull__)) -static inline void cxMapRemove( - CxMap *map, - CxHashKey key -) { - (void) map->cl->remove(map, key, true); -} - -/** - * Detaches a key/value-pair from the map by using the key - * without invoking the destructor. - * - * In general, you should only use this function if the map does not own - * the data and there is a valid reference to the data somewhere else - * in the program. In all other cases it is preferable to use - * cxMapRemove() or cxMapRemoveAndGet(). - * - * @param map the map - * @param key the key - * @see cxMapRemove() - * @see cxMapRemoveAndGet() - */ -__attribute__((__nonnull__)) -static inline void cxMapDetach( - CxMap *map, - CxHashKey key -) { - (void) map->cl->remove(map, key, false); -} - -/** - * Removes a key/value-pair from the map by using the key. - * - * This function can be used when the map is storing pointers, - * in order to retrieve the pointer from the map without invoking - * any destructor function. Sometimes you do not want the pointer - * to be returned - in that case (instead of suppressing the "unused - * result" warning) you can use cxMapDetach(). - * - * If this map is not storing pointers, this function behaves like - * cxMapRemove() and returns \c NULL. - * - * @param map the map - * @param key the key - * @return the stored pointer or \c NULL if either the key is not present - * in the map or the map is not storing pointers - * @see cxMapStorePointers() - * @see cxMapDetach() - */ -__attribute__((__nonnull__, __warn_unused_result__)) -static inline void *cxMapRemoveAndGet( - CxMap *map, - CxHashKey key -) { - return map->cl->remove(map, key, !map->store_pointer); -} // TODO: set-like map operations (union, intersect, difference) @@ -413,8 +312,644 @@ return map->cl->mut_iterator(map); } -#ifdef __cplusplus +#ifdef __cplusplus +} // end the extern "C" block here, because we want to start overloading + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +__attribute__((__nonnull__)) +static inline int cxMapPut( + CxMap *map, + CxHashKey const &key, + void *value +) { + return map->cl->put(map, key, value); +} + + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +__attribute__((__nonnull__)) +static inline int cxMapPut( + CxMap *map, + cxstring const &key, + void *value +) { + return map->cl->put(map, cx_hash_key_cxstr(key), value); +} + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +__attribute__((__nonnull__)) +static inline int cxMapPut( + CxMap *map, + char const *key, + void *value +) { + return map->cl->put(map, cx_hash_key_str(key), value); +} + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cxMapGet( + CxMap const *map, + CxHashKey const &key +) { + return map->cl->get(map, key); +} + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cxMapGet( + CxMap const *map, + cxstring const &key +) { + return map->cl->get(map, cx_hash_key_cxstr(key)); +} + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cxMapGet( + CxMap const *map, + char const *key +) { + return map->cl->get(map, cx_hash_key_str(key)); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * Always invokes the destructor function, if any, on the removed element. + * If this map is storing pointers and you just want to retrieve the pointer + * without invoking the destructor, use cxMapRemoveAndGet(). + * If you just want to detach the element from the map without invoking the + * destructor or returning the element, use cxMapDetach(). + * + * @param map the map + * @param key the key + * @see cxMapRemoveAndGet() + * @see cxMapDetach() + */ +__attribute__((__nonnull__)) +static inline void cxMapRemove( + CxMap *map, + CxHashKey const &key +) { + (void) map->cl->remove(map, key, true); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * Always invokes the destructor function, if any, on the removed element. + * If this map is storing pointers and you just want to retrieve the pointer + * without invoking the destructor, use cxMapRemoveAndGet(). + * If you just want to detach the element from the map without invoking the + * destructor or returning the element, use cxMapDetach(). + * + * @param map the map + * @param key the key + * @see cxMapRemoveAndGet() + * @see cxMapDetach() + */ +__attribute__((__nonnull__)) +static inline void cxMapRemove( + CxMap *map, + cxstring const &key +) { + (void) map->cl->remove(map, cx_hash_key_cxstr(key), true); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * Always invokes the destructor function, if any, on the removed element. + * If this map is storing pointers and you just want to retrieve the pointer + * without invoking the destructor, use cxMapRemoveAndGet(). + * If you just want to detach the element from the map without invoking the + * destructor or returning the element, use cxMapDetach(). + * + * @param map the map + * @param key the key + * @see cxMapRemoveAndGet() + * @see cxMapDetach() + */ +__attribute__((__nonnull__)) +static inline void cxMapRemove( + CxMap *map, + char const *key +) { + (void) map->cl->remove(map, cx_hash_key_str(key), true); +} + +/** + * Detaches a key/value-pair from the map by using the key + * without invoking the destructor. + * + * In general, you should only use this function if the map does not own + * the data and there is a valid reference to the data somewhere else + * in the program. In all other cases it is preferable to use + * cxMapRemove() or cxMapRemoveAndGet(). + * + * @param map the map + * @param key the key + * @see cxMapRemove() + * @see cxMapRemoveAndGet() + */ +__attribute__((__nonnull__)) +static inline void cxMapDetach( + CxMap *map, + CxHashKey const &key +) { + (void) map->cl->remove(map, key, false); +} + +/** + * Detaches a key/value-pair from the map by using the key + * without invoking the destructor. + * + * In general, you should only use this function if the map does not own + * the data and there is a valid reference to the data somewhere else + * in the program. In all other cases it is preferable to use + * cxMapRemove() or cxMapRemoveAndGet(). + * + * @param map the map + * @param key the key + * @see cxMapRemove() + * @see cxMapRemoveAndGet() + */ +__attribute__((__nonnull__)) +static inline void cxMapDetach( + CxMap *map, + cxstring const &key +) { + (void) map->cl->remove(map, cx_hash_key_cxstr(key), false); +} + +/** + * Detaches a key/value-pair from the map by using the key + * without invoking the destructor. + * + * In general, you should only use this function if the map does not own + * the data and there is a valid reference to the data somewhere else + * in the program. In all other cases it is preferable to use + * cxMapRemove() or cxMapRemoveAndGet(). + * + * @param map the map + * @param key the key + * @see cxMapRemove() + * @see cxMapRemoveAndGet() + */ +__attribute__((__nonnull__)) +static inline void cxMapDetach( + CxMap *map, + char const *key +) { + (void) map->cl->remove(map, cx_hash_key_str(key), false); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * This function can be used when the map is storing pointers, + * in order to retrieve the pointer from the map without invoking + * any destructor function. Sometimes you do not want the pointer + * to be returned - in that case (instead of suppressing the "unused + * result" warning) you can use cxMapDetach(). + * + * If this map is not storing pointers, this function behaves like + * cxMapRemove() and returns \c NULL. + * + * @param map the map + * @param key the key + * @return the stored pointer or \c NULL if either the key is not present + * in the map or the map is not storing pointers + * @see cxMapStorePointers() + * @see cxMapDetach() + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cxMapRemoveAndGet( + CxMap *map, + CxHashKey key +) { + return map->cl->remove(map, key, !map->store_pointer); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * This function can be used when the map is storing pointers, + * in order to retrieve the pointer from the map without invoking + * any destructor function. Sometimes you do not want the pointer + * to be returned - in that case (instead of suppressing the "unused + * result" warning) you can use cxMapDetach(). + * + * If this map is not storing pointers, this function behaves like + * cxMapRemove() and returns \c NULL. + * + * @param map the map + * @param key the key + * @return the stored pointer or \c NULL if either the key is not present + * in the map or the map is not storing pointers + * @see cxMapStorePointers() + * @see cxMapDetach() + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cxMapRemoveAndGet( + CxMap *map, + cxstring key +) { + return map->cl->remove(map, cx_hash_key_cxstr(key), !map->store_pointer); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * This function can be used when the map is storing pointers, + * in order to retrieve the pointer from the map without invoking + * any destructor function. Sometimes you do not want the pointer + * to be returned - in that case (instead of suppressing the "unused + * result" warning) you can use cxMapDetach(). + * + * If this map is not storing pointers, this function behaves like + * cxMapRemove() and returns \c NULL. + * + * @param map the map + * @param key the key + * @return the stored pointer or \c NULL if either the key is not present + * in the map or the map is not storing pointers + * @see cxMapStorePointers() + * @see cxMapDetach() + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cxMapRemoveAndGet( + CxMap *map, + char const *key +) { + return map->cl->remove(map, cx_hash_key_str(key), !map->store_pointer); } -#endif + +#else // __cplusplus + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +__attribute__((__nonnull__)) +static inline int cx_map_put( + CxMap *map, + CxHashKey key, + void *value +) { + return map->cl->put(map, key, value); +} + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +__attribute__((__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); +} + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +__attribute__((__nonnull__)) +static inline int cx_map_put_str( + CxMap *map, + char const *key, + void *value +) { + return map->cl->put(map, cx_hash_key_str(key), value); +} + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +#define cxMapPut(map, key, value) _Generic((key), \ + CxHashKey: cx_map_put, \ + cxstring: cx_map_put_cxstr, \ + char*: cx_map_put_str) \ + (map, key, value) + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cx_map_get( + CxMap const *map, + CxHashKey key +) { + return map->cl->get(map, key); +} + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cx_map_get_cxstr( + CxMap const *map, + cxstring key +) { + return map->cl->get(map, cx_hash_key_cxstr(key)); +} + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cx_map_get_str( + CxMap const *map, + char const *key +) { + return map->cl->get(map, cx_hash_key_str(key)); +} + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +#define cxMapGet(map, key) _Generic((key), \ + CxHashKey: cx_map_get, \ + cxstring: cx_map_get_cxstr, \ + char*: cx_map_get_str) \ + (map, key) + +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + */ +__attribute__((__nonnull__)) +static inline void cx_map_remove( + CxMap *map, + CxHashKey key +) { + (void) map->cl->remove(map, key, true); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + */ +__attribute__((__nonnull__)) +static inline void cx_map_remove_cxstr( + CxMap *map, + cxstring key +) { + (void) map->cl->remove(map, cx_hash_key_cxstr(key), true); +} -#endif // UCX_MAP_H \ No newline at end of file +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + */ +__attribute__((__nonnull__)) +static inline void cx_map_remove_str( + CxMap *map, + char const *key +) { + (void) map->cl->remove(map, cx_hash_key_str(key), true); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * Always invokes the destructor function, if any, on the removed element. + * If this map is storing pointers and you just want to retrieve the pointer + * without invoking the destructor, use cxMapRemoveAndGet(). + * If you just want to detach the element from the map without invoking the + * destructor or returning the element, use cxMapDetach(). + * + * @param map the map + * @param key the key + * @see cxMapRemoveAndGet() + * @see cxMapDetach() + */ +#define cxMapRemove(map, key) _Generic((key), \ + CxHashKey: cx_map_remove, \ + cxstring: cx_map_remove_cxstr, \ + char*: cx_map_remove_str) \ + (map, key) + +/** + * Detaches a key/value-pair from the map by using the key + * without invoking the destructor. + * + * @param map the map + * @param key the key + */ +__attribute__((__nonnull__)) +static inline void cx_map_detach( + CxMap *map, + CxHashKey key +) { + (void) map->cl->remove(map, key, false); +} + +/** + * Detaches a key/value-pair from the map by using the key + * without invoking the destructor. + * + * @param map the map + * @param key the key + */ +__attribute__((__nonnull__)) +static inline void cx_map_detach_cxstr( + CxMap *map, + cxstring key +) { + (void) map->cl->remove(map, cx_hash_key_cxstr(key), false); +} + +/** + * Detaches a key/value-pair from the map by using the key + * without invoking the destructor. + * + * @param map the map + * @param key the key + */ +__attribute__((__nonnull__)) +static inline void cx_map_detach_str( + CxMap *map, + char const *key +) { + (void) map->cl->remove(map, cx_hash_key_str(key), false); +} + +/** + * Detaches a key/value-pair from the map by using the key + * without invoking the destructor. + * + * In general, you should only use this function if the map does not own + * the data and there is a valid reference to the data somewhere else + * in the program. In all other cases it is preferable to use + * cxMapRemove() or cxMapRemoveAndGet(). + * + * @param map the map + * @param key the key + * @see cxMapRemove() + * @see cxMapRemoveAndGet() + */ +#define cxMapDetach(map, key) _Generic((key), \ + CxHashKey: cx_map_detach, \ + cxstring: cx_map_detach_cxstr, \ + char*: cx_map_detach_str) \ + (map, key) + +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + * @return the stored pointer or \c NULL if either the key is not present + * in the map or the map is not storing pointers + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cx_map_remove_and_get( + CxMap *map, + CxHashKey key +) { + return map->cl->remove(map, key, !map->store_pointer); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + * @return the stored pointer or \c NULL if either the key is not present + * in the map or the map is not storing pointers + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cx_map_remove_and_get_cxstr( + CxMap *map, + cxstring key +) { + return map->cl->remove(map, cx_hash_key_cxstr(key), !map->store_pointer); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + * @return the stored pointer or \c NULL if either the key is not present + * in the map or the map is not storing pointers + */ +__attribute__((__nonnull__, __warn_unused_result__)) +static inline void *cx_map_remove_and_get_str( + CxMap *map, + char const *key +) { + return map->cl->remove(map, cx_hash_key_str(key), !map->store_pointer); +} + +/** + * Removes a key/value-pair from the map by using the key. + * + * This function can be used when the map is storing pointers, + * in order to retrieve the pointer from the map without invoking + * any destructor function. Sometimes you do not want the pointer + * to be returned - in that case (instead of suppressing the "unused + * result" warning) you can use cxMapDetach(). + * + * If this map is not storing pointers, this function behaves like + * cxMapRemove() and returns \c NULL. + * + * @param map the map + * @param key the key + * @return the stored pointer or \c NULL if either the key is not present + * in the map or the map is not storing pointers + * @see cxMapStorePointers() + * @see cxMapDetach() + */ +#define cxMapRemoveAndGet(map, key) _Generic((key), \ + CxHashKey: cx_map_remove_and_get, \ + cxstring: cx_map_remove_and_get_cxstr, \ + char*: cx_map_remove_and_get_str) \ + (map, key) + +#endif // __cplusplus + +#endif // UCX_MAP_H
--- a/src/hash_map.c Fri Apr 21 18:38:18 2023 +0200 +++ b/src/hash_map.c Fri Apr 21 19:50:43 2023 +0200 @@ -419,7 +419,7 @@ }; CxMap *cxHashMapCreate( - CxAllocator *allocator, + CxAllocator const *allocator, size_t itemsize, size_t buckets ) {
--- a/tests/CMakeLists.txt Fri Apr 21 18:38:18 2023 +0200 +++ b/tests/CMakeLists.txt Fri Apr 21 19:50:43 2023 +0200 @@ -26,6 +26,7 @@ test_tree.cpp test_hash_key.cpp test_map.cpp + test_map_generics.c test_basic_mempool.cpp test_printf.cpp selftest.cpp
--- a/tests/test_map.cpp Fri Apr 21 18:38:18 2023 +0200 +++ b/tests/test_map.cpp Fri Apr 21 19:50:43 2023 +0200 @@ -30,6 +30,7 @@ #include "cx/utils.h" #include "cx/string.h" #include "util_allocator.h" +#include "test_map_generics.h" #include <gtest/gtest.h> #include <unordered_map> @@ -74,7 +75,7 @@ auto keyiter = cxMapIteratorKeys(map); std::unordered_set<std::string> keys; cx_foreach(CxHashKey*, elem, keyiter) { - keys.insert(std::string(reinterpret_cast<char const*>(elem->data), elem->len)); + keys.insert(std::string(reinterpret_cast<char const *>(elem->data), elem->len)); } EXPECT_EQ(keyiter.index, map->size); ASSERT_EQ(keys.size(), map->size); @@ -103,7 +104,8 @@ auto pairiter = cxMapIterator(map); std::unordered_map<std::string, std::string> pairs; cx_foreach(CxMapEntry*, entry, pairiter) { - pairs[std::string(reinterpret_cast<char const*>(entry->key->data), entry->key->len)] = std::string((char *) entry->value); + pairs[std::string(reinterpret_cast<char const *>(entry->key->data), entry->key->len)] = std::string( + (char *) entry->value); } EXPECT_EQ(pairiter.index, map->size); ASSERT_EQ(pairs.size(), refmap.size()); @@ -205,26 +207,26 @@ CxTestingAllocator allocator; auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 4); - cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1"); - cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2"); - cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3"); - cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4"); - cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5"); - cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6"); + cxMapPut(map, "key 1", (void *) "val 1"); + cxMapPut(map, "key 2", (void *) "val 2"); + cxMapPut(map, "key 3", (void *) "val 3"); + cxMapPut(map, "key 4", (void *) "val 4"); + cxMapPut(map, "key 5", (void *) "val 5"); + cxMapPut(map, "key 6", (void *) "val 6"); auto iter = cxMapMutIterator(map); cx_foreach(CxMapEntry*, entry, iter) { - if (reinterpret_cast<char const*>(entry->key->data)[4] % 2 == 1) cxIteratorFlagRemoval(iter); + if (reinterpret_cast<char const *>(entry->key->data)[4] % 2 == 1) cxIteratorFlagRemoval(iter); } EXPECT_EQ(map->size, 3); EXPECT_EQ(iter.index, map->size); - EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr); - EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 2")), nullptr); - EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr); - EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 4")), nullptr); - EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 5")), nullptr); - EXPECT_NE(cxMapGet(map, cx_hash_key_str("key 6")), nullptr); + EXPECT_EQ(cxMapGet(map, "key 1"), nullptr); + EXPECT_NE(cxMapGet(map, "key 2"), nullptr); + EXPECT_EQ(cxMapGet(map, "key 3"), nullptr); + EXPECT_NE(cxMapGet(map, "key 4"), nullptr); + EXPECT_EQ(cxMapGet(map, "key 5"), nullptr); + EXPECT_NE(cxMapGet(map, "key 6"), nullptr); cxMapDestroy(map); EXPECT_TRUE(allocator.verify()); @@ -234,12 +236,12 @@ CxTestingAllocator allocator; auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 8); - cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1"); - cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2"); - cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3"); - cxMapPut(map, cx_hash_key_str("key 4"), (void *) "val 4"); - cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5"); - cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6"); + cxMapPut(map, "key 1", (void *) "val 1"); + cxMapPut(map, "key 2", (void *) "val 2"); + cxMapPut(map, "key 3", (void *) "val 3"); + cxMapPut(map, "key 4", (void *) "val 4"); + cxMapPut(map, "key 5", (void *) "val 5"); + cxMapPut(map, "key 6", (void *) "val 6"); // 6/8 does not exceed 0.75, therefore the function should not rehash int result = cxMapRehash(map); @@ -254,32 +256,32 @@ CxTestingAllocator allocator; auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 7); - cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1"); - cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2"); - cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3"); - cxMapPut(map, cx_hash_key_str("foo 4"), (void *) "val 4"); - cxMapPut(map, cx_hash_key_str("key 5"), (void *) "val 5"); - cxMapPut(map, cx_hash_key_str("key 6"), (void *) "val 6"); - cxMapPut(map, cx_hash_key_str("bar 7"), (void *) "val 7"); - cxMapPut(map, cx_hash_key_str("key 8"), (void *) "val 8"); - cxMapPut(map, cx_hash_key_str("key 9"), (void *) "val 9"); - cxMapPut(map, cx_hash_key_str("key 10"), (void *) "val 10"); + cxMapPut(map, "key 1", (void *) "val 1"); + cxMapPut(map, "key 2", (void *) "val 2"); + cxMapPut(map, "key 3", (void *) "val 3"); + cxMapPut(map, "foo 4", (void *) "val 4"); + cxMapPut(map, "key 5", (void *) "val 5"); + cxMapPut(map, "key 6", (void *) "val 6"); + cxMapPut(map, "bar 7", (void *) "val 7"); + cxMapPut(map, "key 8", (void *) "val 8"); + cxMapPut(map, "key 9", (void *) "val 9"); + cxMapPut(map, "key 10", (void *) "val 10"); int result = cxMapRehash(map); EXPECT_EQ(result, 0); EXPECT_EQ(reinterpret_cast<struct cx_hash_map_s *>(map)->bucket_count, 25); EXPECT_EQ(map->size, 10); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 1")), "val 1"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 2")), "val 2"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 3")), "val 3"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("foo 4")), "val 4"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 5")), "val 5"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 6")), "val 6"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("bar 7")), "val 7"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 8")), "val 8"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 9")), "val 9"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cx_hash_key_str("key 10")), "val 10"), 0); + EXPECT_STREQ((char *) cxMapGet(map, "key 1"), "val 1"); + EXPECT_STREQ((char *) cxMapGet(map, "key 2"), "val 2"); + EXPECT_STREQ((char *) cxMapGet(map, "key 3"), "val 3"); + EXPECT_STREQ((char *) cxMapGet(map, "foo 4"), "val 4"); + EXPECT_STREQ((char *) cxMapGet(map, "key 5"), "val 5"); + EXPECT_STREQ((char *) cxMapGet(map, "key 6"), "val 6"); + EXPECT_STREQ((char *) cxMapGet(map, "bar 7"), "val 7"); + EXPECT_STREQ((char *) cxMapGet(map, "key 8"), "val 8"); + EXPECT_STREQ((char *) cxMapGet(map, "key 9"), "val 9"); + EXPECT_STREQ((char *) cxMapGet(map, "key 10"), "val 10"); cxMapDestroy(map); EXPECT_TRUE(allocator.verify()); @@ -289,18 +291,18 @@ CxTestingAllocator allocator; auto map = cxHashMapCreate(&allocator, CX_STORE_POINTERS, 0); - cxMapPut(map, cx_hash_key_str("key 1"), (void *) "val 1"); - cxMapPut(map, cx_hash_key_str("key 2"), (void *) "val 2"); - cxMapPut(map, cx_hash_key_str("key 3"), (void *) "val 3"); + cxMapPut(map, "key 1", (void *) "val 1"); + cxMapPut(map, "key 2", (void *) "val 2"); + cxMapPut(map, "key 3", (void *) "val 3"); EXPECT_EQ(map->size, 3); cxMapClear(map); EXPECT_EQ(map->size, 0); - EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 1")), nullptr); - EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 2")), nullptr); - EXPECT_EQ(cxMapGet(map, cx_hash_key_str("key 3")), nullptr); + EXPECT_EQ(cxMapGet(map, "key 1"), nullptr); + EXPECT_EQ(cxMapGet(map, "key 2"), nullptr); + EXPECT_EQ(cxMapGet(map, "key 3"), nullptr); cxMapDestroy(map); EXPECT_TRUE(allocator.verify()); @@ -319,22 +321,22 @@ auto s5 = CX_STR("setup"); // put them into the map - cxMapPut(map, cx_hash_key_str("s1"), &s1); - cxMapPut(map, cx_hash_key_str("s2"), &s2); - cxMapPut(map, cx_hash_key_str("s3"), &s3); - cxMapPut(map, cx_hash_key_str("s4"), &s4); + cxMapPut(map, "s1", &s1); + cxMapPut(map, "s2", &s2); + cxMapPut(map, "s3", &s3); + cxMapPut(map, "s4", &s4); // overwrite a value - cxMapPut(map, cx_hash_key_str("s1"), &s5); + cxMapPut(map, "s1", &s5); // look up a string - auto s3p = reinterpret_cast<cxstring *>(cxMapGet(map, cx_hash_key_str("s3"))); + auto s3p = reinterpret_cast<cxstring *>(cxMapGet(map, "s3")); EXPECT_EQ(s3p->length, s3.length); EXPECT_EQ(s3p->ptr, s3.ptr); EXPECT_NE(s3p, &s3); // remove a string - cxMapRemove(map, cx_hash_key_str("s2")); + cxMapRemove(map, "s2"); // iterate auto ref = std::vector{s5.ptr, s3.ptr, s4.ptr}; @@ -405,7 +407,7 @@ { auto iter = cxMapMutIteratorKeys(map); cx_foreach(CxHashKey*, key, iter) { - if (reinterpret_cast<char const*>(key->data)[4] == '1') cxIteratorFlagRemoval(iter); + if (reinterpret_cast<char const *>(key->data)[4] == '1') cxIteratorFlagRemoval(iter); } } { @@ -447,3 +449,26 @@ verify_any_destructor(map); EXPECT_TRUE(allocator.verify()); } + +TEST(CxHashMap, Generics) { + CxTestingAllocator allocator; + auto map = test_map_generics_step_1(&allocator); + + EXPECT_EQ(map->size, 3); + EXPECT_STREQ((char *) cxMapGet(map, "test"), "test"); + EXPECT_STREQ((char *) cxMapGet(map, "foo"), "bar"); + EXPECT_STREQ((char *) cxMapGet(map, "hallo"), "welt"); + + test_map_generics_step_2(map); + + EXPECT_EQ(map->size, 2); + EXPECT_STREQ((char *) cxMapGet(map, "key"), "value"); + EXPECT_STREQ((char *) cxMapGet(map, "foo"), "bar"); + + test_map_generics_step_3(map); + + EXPECT_EQ(map->size, 0); + + cxMapDestroy(map); + EXPECT_TRUE(allocator.verify()); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_map_generics.c Fri Apr 21 19:50:43 2023 +0200 @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include "test_map_generics.h" +#include "cx/hash_map.h" + +CxMap *test_map_generics_step_1(CxAllocator const * allocator) { + CxMap *map = cxHashMapCreate(allocator, sizeof(cxstring), 0); + + cxMapPut(map, "test", "test"); + cxMapPut(map, CX_STR("foo"), "bar"); + cxMapPut(map, cx_str("hallo"), "welt"); + + return map; +} + +void test_map_generics_step_2(CxMap *map) { + // note: we don't have a destructor here, so remove and detach are the same + cxMapRemove(map, cx_str("test")); + cxMapDetach(map, "hallo"); + cxMapPut(map, cx_hash_key_str("key"), "value"); +} + +void test_map_generics_step_3(CxMap *map) { + void *r; + r = cxMapRemoveAndGet(map, "key"); + r = cxMapRemoveAndGet(map, cx_str("foo")); + if (r != NULL) map->size = 47; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_map_generics.h Fri Apr 21 19:50:43 2023 +0200 @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#ifndef UCX_TEST_MAP_GENERICS_H +#define UCX_TEST_MAP_GENERICS_H + +#include "cx/map.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CxMap *test_map_generics_step_1(CxAllocator const *); + +void test_map_generics_step_2(CxMap *); + +void test_map_generics_step_3(CxMap *); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif //UCX_TEST_MAP_GENERICS_H