# HG changeset patch # User Mike Becker # Date 1654716811 -7200 # Node ID 69a83fad8a357fde0a2fefe02514ef79e03fec7e # Parent fd3368c20413f69b3c2eb0738555fa7bcf8b4f95 improve hash key handling diff -r fd3368c20413 -r 69a83fad8a35 src/CMakeLists.txt --- a/src/CMakeLists.txt Fri May 27 17:40:27 2022 +0200 +++ b/src/CMakeLists.txt Wed Jun 08 21:33:31 2022 +0200 @@ -5,7 +5,7 @@ linked_list.c tree.c buffer.c - map.c + hash_key.c hash_map.c ) set(headers @@ -18,6 +18,7 @@ cx/tree.h cx/buffer.h cx/map.h + cx/hash_key.h cx/hash_map.h ) diff -r fd3368c20413 -r 69a83fad8a35 src/cx/common.h --- a/src/cx/common.h Fri May 27 17:40:27 2022 +0200 +++ b/src/cx/common.h Wed Jun 08 21:33:31 2022 +0200 @@ -94,25 +94,6 @@ #include /** - * Structure that contains a pointer to arbitrary data. - */ -struct cx_data_ptr_s { - /** - * A pointer to the data. - */ - unsigned char const *data; - /** - * The length of the data. - */ - size_t len; -}; - -/** - * Type for a data pointer with length information. - */ -typedef struct cx_data_ptr_s CxDataPtr; - -/** * Function pointer compatible with fwrite-like functions. */ typedef size_t (*cx_write_func)( diff -r fd3368c20413 -r 69a83fad8a35 src/cx/hash_key.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cx/hash_key.h Wed Jun 08 21:33:31 2022 +0200 @@ -0,0 +1,125 @@ +/* + * 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 hash_key.h + * \brief Interface for map implementations. + * \author Mike Becker + * \author Olaf Wintermann + * \version 3.0 + * \copyright 2-Clause BSD License + */ + + +#ifndef UCX_HASH_KEY_H +#define UCX_HASH_KEY_H + +#include "stddef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Internal structure for a key within a hash map. */ +struct cx_hash_key_s { + /** The key data. */ + union { + unsigned char *bytes; + unsigned char const *cbytes; + char const *cstr; + char *str; + void *obj; + } data; + /** + * The key data length. + */ + size_t len; + /** The hash value of the key data. */ + unsigned hash; +}; + +/** + * Type for a hash key. + */ +typedef struct cx_hash_key_s CxHashKey; + +/** + * Computes a murmur hash-2. + * + * You need to initialize data and len in the key struct. + * The hash is then directly written to that struct. + * + * @param key the key, the hash shall be computed for + */ +void cx_hash_murmur(CxHashKey *key); + +/** + * Computes a hash key from a string. + * + * The string needs to be zero-terminated. + * + * @param str the string + * @return the hash key + */ +__attribute__((__warn_unused_result__)) +CxHashKey cx_hash_key_str(char const *str); + +/** + * Computes a hash key from a byte array. + * + * @param bytes the array + * @param len the length + * @return the hash key + */ +__attribute__((__warn_unused_result__)) +CxHashKey cx_hash_key_bytes( + unsigned char const *bytes, + size_t len +); + +/** + * Computes a hash key for an arbitrary object. + * + * The computation uses the in-memory representation that might not be + * the same on different platforms. Therefore, this hash should not be + * used for data exchange with different machines. + * + * @param obj a pointer to an arbitrary object + * @param len the length of object in memory + * @return the hash key + */ +__attribute__((__warn_unused_result__)) +CxHashKey cx_hash_key( + void *obj, + size_t len +); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* UCX_HASH_KEY_H */ diff -r fd3368c20413 -r 69a83fad8a35 src/cx/hash_map.h --- a/src/cx/hash_map.h Fri May 27 17:40:27 2022 +0200 +++ b/src/cx/hash_map.h Wed Jun 08 21:33:31 2022 +0200 @@ -26,8 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ /** - * \file map.h - * \brief Interface for map implementations. + * \file hash_map.h + * \brief Hash map implementation. * \author Mike Becker * \author Olaf Wintermann * \version 3.0 @@ -43,18 +43,6 @@ extern "C" { #endif -/** Internal structure for a key within a hash map. */ -struct cx_hash_map_key_s { - /** The key data. */ - unsigned char *data; - /** - * The key data length. - */ - size_t len; - /** The hash value of the key data. */ - unsigned hash; -}; - /** Internal structure for an element of a hash map. */ struct cx_hash_map_element_s { /** The value data. */ @@ -64,7 +52,7 @@ struct cx_hash_map_element_s *next; /** The corresponding key. */ - struct cx_hash_map_key_s key; + CxHashKey key; }; /** diff -r fd3368c20413 -r 69a83fad8a35 src/cx/map.h --- a/src/cx/map.h Fri May 27 17:40:27 2022 +0200 +++ b/src/cx/map.h Wed Jun 08 21:33:31 2022 +0200 @@ -40,6 +40,7 @@ #include "common.h" #include "allocator.h" #include "iterator.h" +#include "hash_key.h" #ifdef __cplusplus extern "C" { @@ -87,7 +88,7 @@ __attribute__((__nonnull__)) int (*put)( CxMap *map, - CxDataPtr key, + CxHashKey key, void *value ); @@ -97,7 +98,7 @@ __attribute__((__nonnull__, __warn_unused_result__)) void *(*get)( CxMap const *map, - CxDataPtr key + CxHashKey key ); /** @@ -106,7 +107,7 @@ __attribute__((__nonnull__, __warn_unused_result__)) void *(*remove)( CxMap *map, - CxDataPtr key + CxHashKey key ); /** @@ -135,7 +136,7 @@ /** * A pointer to the key. */ - CxDataPtr const *key; + CxHashKey const *key; /** * A pointer to the value. */ @@ -176,7 +177,7 @@ __attribute__((__nonnull__)) static inline int cxMapPut( CxMap *map, - CxDataPtr key, + CxHashKey key, void *value ) { return map->cl->put(map, key, value); @@ -192,7 +193,7 @@ __attribute__((__nonnull__, __warn_unused_result__)) static inline void *cxMapGet( CxMap const *map, - CxDataPtr key + CxHashKey key ) { return map->cl->get(map, key); } @@ -207,7 +208,7 @@ __attribute__((__nonnull__, __warn_unused_result__)) static inline void *cxMapRemove( CxMap *map, - CxDataPtr key + CxHashKey key ) { return map->cl->remove(map, key); } @@ -262,15 +263,6 @@ return map->cl->iterator(map); } -/** - * Convenience function to make a key from a NULL-terminated string. - * - * @param str the NULL-terminated string - * @return the string wrapped to be used as a map key - */ -__attribute__((__nonnull__, __warn_unused_result__)) -CxDataPtr cxMapKeyStr(char const *str); - #ifdef __cplusplus } #endif diff -r fd3368c20413 -r 69a83fad8a35 src/hash_key.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hash_key.c Wed Jun 08 21:33:31 2022 +0200 @@ -0,0 +1,107 @@ +/* + * 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 "cx/hash_key.h" +#include + +void cx_hash_murmur(CxHashKey *key) { + size_t len = key->len; + unsigned char const *data = key->data.cbytes; + + unsigned m = 0x5bd1e995; + unsigned r = 24; + unsigned h = 25 ^ len; + unsigned i = 0; + while (len >= 4) { + unsigned k = data[i + 0] & 0xFF; + k |= (data[i + 1] & 0xFF) << 8; + k |= (data[i + 2] & 0xFF) << 16; + k |= (data[i + 3] & 0xFF) << 24; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + i += 4; + len -= 4; + } + + switch (len) { + case 3: + h ^= (data[i + 2] & 0xFF) << 16; + __attribute__((__fallthrough__)); + case 2: + h ^= (data[i + 1] & 0xFF) << 8; + __attribute__((__fallthrough__)); + case 1: + h ^= (data[i + 0] & 0xFF); + h *= m; + __attribute__((__fallthrough__)); + default: + /* do nothing */; + } + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + key->hash = h; +} + +CxHashKey cx_hash_key_str(char const *str) { + CxHashKey key; + key.data.cstr = str; + key.len = str == NULL ? 0 : (1 + strlen(str)); + cx_hash_murmur(&key); + return key; +} + +CxHashKey cx_hash_key_bytes( + unsigned char const *bytes, + size_t len +) { + CxHashKey key; + key.data.cbytes = bytes; + key.len = len; + cx_hash_murmur(&key); + return key; +} + +CxHashKey cx_hash_key( + void *obj, + size_t len +) { + CxHashKey key; + key.data.obj = obj; + key.len = len; + cx_hash_murmur(&key); + return key; +} diff -r fd3368c20413 -r 69a83fad8a35 src/hash_map.c --- a/src/hash_map.c Fri May 27 17:40:27 2022 +0200 +++ b/src/hash_map.c Wed Jun 08 21:33:31 2022 +0200 @@ -30,60 +30,6 @@ #include "cx/hash_map.h" #include "cx/utils.h" -/** - * Computes a murmur hash-2. - * - * @param data the data to hash - * @param len the length of the data - * @return the murmur hash-2 of the data - */ -static unsigned cx_hash_map_murmur( - unsigned char const *data, - size_t len -) { - unsigned m = 0x5bd1e995; - unsigned r = 24; - unsigned h = 25 ^ len; - unsigned i = 0; - while (len >= 4) { - unsigned k = data[i + 0] & 0xFF; - k |= (data[i + 1] & 0xFF) << 8; - k |= (data[i + 2] & 0xFF) << 16; - k |= (data[i + 3] & 0xFF) << 24; - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - i += 4; - len -= 4; - } - - switch (len) { - case 3: - h ^= (data[i + 2] & 0xFF) << 16; - __attribute__((__fallthrough__)); - case 2: - h ^= (data[i + 1] & 0xFF) << 8; - __attribute__((__fallthrough__)); - case 1: - h ^= (data[i + 0] & 0xFF); - h *= m; - __attribute__((__fallthrough__)); - default: - /* do nothing */; - } - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} - static void cx_hash_map_clear(struct cx_map_s *map) { struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map; cx_for_n(i, hash_map->bucket_count) { @@ -92,7 +38,7 @@ do { struct cx_hash_map_element_s *next = elem->next; // free the key data - cxFree(map->allocator, elem->key.data); + cxFree(map->allocator, elem->key.data.obj); // free the node cxFree(map->allocator, elem); // proceed @@ -119,13 +65,17 @@ static int cx_hash_map_put( CxMap *map, - CxDataPtr key, + CxHashKey key, void *value ) { struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map; CxAllocator *allocator = map->allocator; - unsigned hash = cx_hash_map_murmur(key.data, key.len); + unsigned hash = key.hash; + if (hash == 0) { + cx_hash_murmur(&key); + hash = key.hash; + } size_t slot = hash % hash_map->bucket_count; struct cx_hash_map_element_s *elm = hash_map->buckets[slot]; @@ -151,8 +101,8 @@ if (kd == NULL) { return -1; } - memcpy(kd, key.data, key.len); - e->key.data = kd; + memcpy(kd, key.data.obj, key.len); + e->key.data.obj = kd; e->key.len = key.len; e->key.hash = hash; @@ -187,7 +137,7 @@ prev->next = elm->next; } // free element - cxFree(hash_map->base.allocator, elm->key.data); + cxFree(hash_map->base.allocator, elm->key.data.obj); cxFree(hash_map->base.allocator, elm); // decrease size hash_map->base.size--; @@ -203,19 +153,23 @@ */ static void *cx_hash_map_get_remove( CxMap *map, - CxDataPtr key, + CxHashKey key, bool remove ) { struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map; - unsigned hash = cx_hash_map_murmur(key.data, key.len); + unsigned hash = key.hash; + if (hash == 0) { + cx_hash_murmur(&key); + hash = key.hash; + } size_t slot = hash % hash_map->bucket_count; struct cx_hash_map_element_s *elm = hash_map->buckets[slot]; struct cx_hash_map_element_s *prev = NULL; while (elm && elm->key.hash <= hash) { if (elm->key.hash == hash && elm->key.len == key.len) { - if (memcmp(elm->key.data, key.data, key.len) == 0) { + if (memcmp(elm->key.data.obj, key.data.obj, key.len) == 0) { void *data = elm->data; if (remove) { cx_hash_map_unlink(hash_map, slot, prev, elm); @@ -232,7 +186,7 @@ static void *cx_hash_map_get( CxMap const *map, - CxDataPtr key + CxHashKey key ) { // we can safely cast, because we know when remove=false, the map stays untouched return cx_hash_map_get_remove((CxMap *) map, key, false); @@ -240,7 +194,7 @@ static void *cx_hash_map_remove( CxMap *map, - CxDataPtr key + CxHashKey key ) { return cx_hash_map_get_remove(map, key, true); } diff -r fd3368c20413 -r 69a83fad8a35 src/map.c --- a/src/map.c Fri May 27 17:40:27 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * 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 -#include "cx/map.h" - -CxDataPtr cxMapKeyStr(char const *str) { - CxDataPtr key = {(unsigned char const *) str, 1 + strlen(str)}; - return key; -} \ No newline at end of file diff -r fd3368c20413 -r 69a83fad8a35 test/test_map.cpp --- a/test/test_map.cpp Fri May 27 17:40:27 2022 +0200 +++ b/test/test_map.cpp Wed Jun 08 21:33:31 2022 +0200 @@ -72,9 +72,9 @@ { auto keyiter = cxMapIteratorKeys(map); std::unordered_set keys; - cx_foreach(CxDataPtr*, elem, keyiter) { + cx_foreach(CxHashKey*, elem, keyiter) { // we use that our test keys contain NULL-terminated strings - keys.insert(std::string(reinterpret_cast(elem->data))); + keys.insert(std::string(elem->data.cstr)); } EXPECT_EQ(keyiter.index, map->size); ASSERT_EQ(keys.size(), map->size); @@ -103,7 +103,7 @@ auto pairiter = cxMapIterator(map); std::unordered_map pairs; cx_foreach(CxMapEntry*, entry, pairiter) { - pairs[std::string((char const *) entry->key->data)] = std::string((char *) entry->value); + pairs[std::string(entry->key->data.cstr)] = std::string((char *) entry->value); } EXPECT_EQ(pairiter.index, map->size); ASSERT_EQ(pairs.size(), refmap.size()); @@ -144,7 +144,8 @@ // execute operations and verify results for (auto &&op: ops) { - CxDataPtr key = cxMapKeyStr(op.key); + CxHashKey key = cx_hash_key_str(op.key); + key.hash = 0; // force the hash map to compute the hash if (op.op == map_operation::put) { // execute a put operation and verify that the exact value can be read back refmap[std::string(op.key)] = std::string(op.value); @@ -176,26 +177,26 @@ CxTestingAllocator allocator; auto map = cxHashMapCreate(&allocator, 4); - cxMapPut(map, cxMapKeyStr("key 1"), (void *) "val 1"); - cxMapPut(map, cxMapKeyStr("key 2"), (void *) "val 2"); - cxMapPut(map, cxMapKeyStr("key 3"), (void *) "val 3"); - cxMapPut(map, cxMapKeyStr("key 4"), (void *) "val 4"); - cxMapPut(map, cxMapKeyStr("key 5"), (void *) "val 5"); - cxMapPut(map, cxMapKeyStr("key 6"), (void *) "val 6"); + 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"); auto iter = cxMapIterator(map); cx_foreach(CxMapEntry*, entry, iter) { - if (entry->key->data[4] % 2 == 1) iter.remove = true; + if (entry->key->data.cstr[4] % 2 == 1) iter.remove = true; } EXPECT_EQ(map->size, 3); EXPECT_EQ(iter.index, map->size); - EXPECT_EQ(cxMapGet(map, cxMapKeyStr("key 1")), nullptr); - EXPECT_NE(cxMapGet(map, cxMapKeyStr("key 2")), nullptr); - EXPECT_EQ(cxMapGet(map, cxMapKeyStr("key 3")), nullptr); - EXPECT_NE(cxMapGet(map, cxMapKeyStr("key 4")), nullptr); - EXPECT_EQ(cxMapGet(map, cxMapKeyStr("key 5")), nullptr); - EXPECT_NE(cxMapGet(map, cxMapKeyStr("key 6")), nullptr); + 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); cxMapDestroy(map); EXPECT_TRUE(allocator.verify()); @@ -205,12 +206,12 @@ CxTestingAllocator allocator; auto map = cxHashMapCreate(&allocator, 8); - cxMapPut(map, cxMapKeyStr("key 1"), (void *) "val 1"); - cxMapPut(map, cxMapKeyStr("key 2"), (void *) "val 2"); - cxMapPut(map, cxMapKeyStr("key 3"), (void *) "val 3"); - cxMapPut(map, cxMapKeyStr("key 4"), (void *) "val 4"); - cxMapPut(map, cxMapKeyStr("key 5"), (void *) "val 5"); - cxMapPut(map, cxMapKeyStr("key 6"), (void *) "val 6"); + 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"); // 6/8 does not exceed 0.75, therefore the function should not rehash int result = cxMapRehash(map); @@ -225,26 +226,26 @@ CxTestingAllocator allocator; auto map = cxHashMapCreate(&allocator, 8); - cxMapPut(map, cxMapKeyStr("key 1"), (void *) "val 1"); - cxMapPut(map, cxMapKeyStr("key 2"), (void *) "val 2"); - cxMapPut(map, cxMapKeyStr("key 3"), (void *) "val 3"); - cxMapPut(map, cxMapKeyStr("key 4"), (void *) "val 4"); - cxMapPut(map, cxMapKeyStr("key 5"), (void *) "val 5"); - cxMapPut(map, cxMapKeyStr("key 6"), (void *) "val 6"); - cxMapPut(map, cxMapKeyStr("key 7"), (void *) "val 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("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, cx_hash_key_str("key 7"), (void *) "val 7"); int result = cxMapRehash(map); EXPECT_EQ(result, 0); EXPECT_EQ(reinterpret_cast(map)->bucket_count, 17); EXPECT_EQ(map->size, 7); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cxMapKeyStr("key 1")), "val 1"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cxMapKeyStr("key 2")), "val 2"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cxMapKeyStr("key 3")), "val 3"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cxMapKeyStr("key 4")), "val 4"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cxMapKeyStr("key 5")), "val 5"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cxMapKeyStr("key 6")), "val 6"), 0); - EXPECT_EQ(strcmp((char *) cxMapGet(map, cxMapKeyStr("key 7")), "val 7"), 0); + 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("key 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("key 7")), "val 7"), 0); cxMapDestroy(map); EXPECT_TRUE(allocator.verify());