Wed, 18 May 2022 16:26:32 +0200
#189 declare basic map functions
src/CMakeLists.txt | file | annotate | diff | comparison | revisions | |
src/cx/common.h | file | annotate | diff | comparison | revisions | |
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 |
1.1 --- a/src/CMakeLists.txt Mon May 16 19:25:19 2022 +0200 1.2 +++ b/src/CMakeLists.txt Wed May 18 16:26:32 2022 +0200 1.3 @@ -5,8 +5,10 @@ 1.4 linked_list.c 1.5 tree.c 1.6 buffer.c 1.7 + hash_map.c 1.8 ) 1.9 set(headers 1.10 + cx/common.h 1.11 cx/utils.h 1.12 cx/allocator.h 1.13 cx/iterator.h 1.14 @@ -14,7 +16,9 @@ 1.15 cx/linked_list.h 1.16 cx/tree.h 1.17 cx/buffer.h 1.18 -) 1.19 + cx/map.h 1.20 + cx/hash_map.h 1.21 + ) 1.22 1.23 add_library(ucx SHARED ${sources}) 1.24 add_library(ucx_static STATIC ${sources})
2.1 --- a/src/cx/common.h Mon May 16 19:25:19 2022 +0200 2.2 +++ b/src/cx/common.h Wed May 18 16:26:32 2022 +0200 2.3 @@ -94,6 +94,25 @@ 2.4 #include <stdbool.h> 2.5 2.6 /** 2.7 + * Structure that contains a pointer to arbitrary data. 2.8 + */ 2.9 +struct cx_data_ptr_s { 2.10 + /** 2.11 + * A pointer to the data. 2.12 + */ 2.13 + unsigned const char *data; 2.14 + /** 2.15 + * The length of the data. 2.16 + */ 2.17 + size_t len; 2.18 +}; 2.19 + 2.20 +/** 2.21 + * Type for a data pointer with length information. 2.22 + */ 2.23 +typedef struct cx_data_ptr_s CxDataPtr; 2.24 + 2.25 +/** 2.26 * Function pointer compatible with fwrite-like functions. 2.27 */ 2.28 typedef size_t (*cx_write_func)(
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/cx/hash_map.h Wed May 18 16:26:32 2022 +0200 3.3 @@ -0,0 +1,123 @@ 3.4 +/* 3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3.6 + * 3.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 3.8 + * 3.9 + * Redistribution and use in source and binary forms, with or without 3.10 + * modification, are permitted provided that the following conditions are met: 3.11 + * 3.12 + * 1. Redistributions of source code must retain the above copyright 3.13 + * notice, this list of conditions and the following disclaimer. 3.14 + * 3.15 + * 2. Redistributions in binary form must reproduce the above copyright 3.16 + * notice, this list of conditions and the following disclaimer in the 3.17 + * documentation and/or other materials provided with the distribution. 3.18 + * 3.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 3.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 3.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3.29 + * POSSIBILITY OF SUCH DAMAGE. 3.30 + */ 3.31 +/** 3.32 + * \file map.h 3.33 + * \brief Interface for map implementations. 3.34 + * \author Mike Becker 3.35 + * \author Olaf Wintermann 3.36 + * \version 3.0 3.37 + * \copyright 2-Clause BSD License 3.38 + */ 3.39 + 3.40 +#ifndef UCX_HASH_MAP_H 3.41 +#define UCX_HASH_MAP_H 3.42 + 3.43 +#include "map.h" 3.44 + 3.45 +#ifdef __cplusplus 3.46 +extern "C" { 3.47 +#endif 3.48 + 3.49 +/** Internal structure for a key within a hash map. */ 3.50 +struct cx_hash_map_key_s { 3.51 + /** The key data. */ 3.52 + CxDataPtr data; 3.53 + /** The hash value of the key data. */ 3.54 + unsigned hash; 3.55 +}; 3.56 + 3.57 +/** Internal structure for an element of a hash map. */ 3.58 +struct cx_hash_map_element_s { 3.59 + /** The value data. */ 3.60 + void *data; 3.61 + 3.62 + /** A pointer to the next element in the current bucket. */ 3.63 + struct cx_hash_map_element_s *next; 3.64 + 3.65 + /** The corresponding key. */ 3.66 + struct cx_hash_map_key_s key; 3.67 +}; 3.68 + 3.69 + 3.70 +/** 3.71 + * Creates a new hash map with the specified size using a UcxAllocator. 3.72 + * 3.73 + * @param allocator the allocator to use 3.74 + * @param buckets the initial number of buckets in this hash map 3.75 + * @return a pointer to the new hash map 3.76 + */ 3.77 +CxMap *cxHashMapCreate( 3.78 + CxAllocator *allocator, 3.79 + size_t buckets 3.80 +); 3.81 + 3.82 +/** 3.83 + * Increases the number of buckets, if necessary. 3.84 + * 3.85 + * The load value is \c loadFactor*buckets. If the element count exceeds the load 3.86 + * value, the map needs to be rehashed. Otherwise, no action is performed and 3.87 + * this function simply returns 0. 3.88 + * 3.89 + * The rehashing process ensures, that the number of buckets is at least 3.90 + * \p bucketFactor times the number of stored items. So there is enough room for additional 3.91 + * elements without the need of another soon rehashing. 3.92 + * 3.93 + * You can use this function after filling a map to dramatically increase access performance. 3.94 + * 3.95 + * @note If the specified map is not a hash map, the behavior is undefined. 3.96 + * 3.97 + * @param map the map to rehash 3.98 + * @param loadFactor a percentage threshold for the load of the map 3.99 + * @param bucketFactor a factor for the number of buckets that shall be available after rehashing 3.100 + * @return zero on success, non-zero if a memory allocation error occurred 3.101 + */ 3.102 +__attribute__((__nonnull__)) 3.103 +int cxMapRehash2( 3.104 + CxMap *map, 3.105 + float loadFactor, 3.106 + float bucketFactor 3.107 +); 3.108 + 3.109 +/** 3.110 + * Rehashes the map with load factor 0.75 and bucket factor 2.5. 3.111 + * 3.112 + * @param map the map to rehash 3.113 + * @return zero on success, non-zero if a memory allocation error occurred 3.114 + * @see cxMapRehash2() 3.115 + */ 3.116 +__attribute__((__nonnull__)) 3.117 +static inline int cxMapRehash(CxMap *map) { 3.118 + return cxMapRehash2(map, 0.75f, 2.5f); 3.119 +} 3.120 + 3.121 + 3.122 +#ifdef __cplusplus 3.123 +} // extern "C" 3.124 +#endif 3.125 + 3.126 +#endif // UCX_HASH_MAP_H
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/cx/map.h Wed May 18 16:26:32 2022 +0200 4.3 @@ -0,0 +1,268 @@ 4.4 +/* 4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 4.6 + * 4.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 4.8 + * 4.9 + * Redistribution and use in source and binary forms, with or without 4.10 + * modification, are permitted provided that the following conditions are met: 4.11 + * 4.12 + * 1. Redistributions of source code must retain the above copyright 4.13 + * notice, this list of conditions and the following disclaimer. 4.14 + * 4.15 + * 2. Redistributions in binary form must reproduce the above copyright 4.16 + * notice, this list of conditions and the following disclaimer in the 4.17 + * documentation and/or other materials provided with the distribution. 4.18 + * 4.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 4.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 4.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 4.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 4.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 4.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 4.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4.29 + * POSSIBILITY OF SUCH DAMAGE. 4.30 + */ 4.31 +/** 4.32 + * \file map.h 4.33 + * \brief Interface for map implementations. 4.34 + * \author Mike Becker 4.35 + * \author Olaf Wintermann 4.36 + * \version 3.0 4.37 + * \copyright 2-Clause BSD License 4.38 + */ 4.39 + 4.40 +#ifndef UCX_MAP_H 4.41 +#define UCX_MAP_H 4.42 + 4.43 +#include "common.h" 4.44 +#include "allocator.h" 4.45 +#include "iterator.h" 4.46 + 4.47 +#ifdef __cplusplus 4.48 +extern "C" { 4.49 +#endif 4.50 + 4.51 +/** Type for the UCX map. */ 4.52 +typedef struct cx_map_s CxMap; 4.53 + 4.54 +/** Type for a map entry. */ 4.55 +typedef struct cx_map_entry_s CxMapEntry; 4.56 + 4.57 +/** Type for map class definitions. */ 4.58 +typedef struct cx_map_class_s cx_map_class; 4.59 + 4.60 +/** Structure for the UCX map. */ 4.61 +struct cx_map_s { 4.62 + /** The map class definition. */ 4.63 + cx_map_class *cl; 4.64 + /** An allocator that is used for the map elements. */ 4.65 + CxAllocator *allocator; 4.66 + /** The number of elements currently stored. */ 4.67 + size_t size; 4.68 + // TODO: elemsize + a flag if values shall be copied to the map 4.69 +}; 4.70 + 4.71 +/** 4.72 + * The class definition for arbitrary maps. 4.73 + */ 4.74 +struct cx_map_class_s { 4.75 + /** 4.76 + * Deallocates the entire memory. 4.77 + */ 4.78 + __attribute__((__nonnull__)) 4.79 + void (*destructor)(struct cx_map_s *map); 4.80 + 4.81 + /** 4.82 + * Removes all elements. 4.83 + */ 4.84 + __attribute__((__nonnull__)) 4.85 + void (*clear)(struct cx_map_s *map); 4.86 + 4.87 + /** 4.88 + * Add or overwrite an element. 4.89 + */ 4.90 + __attribute__((__nonnull__)) 4.91 + int (*put)( 4.92 + CxMap *map, 4.93 + CxDataPtr key, 4.94 + void const *value 4.95 + ); 4.96 + 4.97 + /** 4.98 + * Returns an element. 4.99 + */ 4.100 + __attribute__((__nonnull__, __warn_unused_result__)) 4.101 + void *(*get)( 4.102 + CxMap const *map, 4.103 + CxDataPtr key 4.104 + ); 4.105 + 4.106 + /** 4.107 + * Removes an element. 4.108 + */ 4.109 + __attribute__((__nonnull__, __warn_unused_result__)) 4.110 + void *(*remove)( 4.111 + CxMap const *map, 4.112 + CxDataPtr key 4.113 + ); 4.114 + 4.115 + /** 4.116 + * Iterator over the key/value pairs. 4.117 + */ 4.118 + __attribute__((__nonnull__, __warn_unused_result__)) 4.119 + CxIterator (*iterator)(CxMap const *map); 4.120 + 4.121 + /** 4.122 + * Iterator over the keys. 4.123 + */ 4.124 + __attribute__((__nonnull__, __warn_unused_result__)) 4.125 + CxIterator (*iterator_keys)(CxMap const *map); 4.126 + 4.127 + /** 4.128 + * Iterator over the values. 4.129 + */ 4.130 + __attribute__((__nonnull__, __warn_unused_result__)) 4.131 + CxIterator (*iterator_values)(CxMap const *map); 4.132 +}; 4.133 + 4.134 +/** 4.135 + * A map entry. 4.136 + */ 4.137 +struct cx_map_entry_s { 4.138 + /** 4.139 + * The key. 4.140 + */ 4.141 + CxDataPtr key; 4.142 + /** 4.143 + * The value. 4.144 + */ 4.145 + void const *value; 4.146 +}; 4.147 + 4.148 + 4.149 +/** 4.150 + * Deallocates the memory of the specified map. 4.151 + * 4.152 + * @param map the map to be destroyed 4.153 + */ 4.154 +__attribute__((__nonnull__)) 4.155 +static inline void cxMapDestroy(CxMap *map) { 4.156 + // TODO: likely to add auto-free feature for contents in the future 4.157 + map->cl->destructor(map); 4.158 +} 4.159 + 4.160 + 4.161 +/** 4.162 + * Clears a map by removing all elements. 4.163 + * 4.164 + * @param map the map to be cleared 4.165 + */ 4.166 +__attribute__((__nonnull__)) 4.167 +static inline void cxMapClear(CxMap *map) { 4.168 + map->cl->clear(map); 4.169 +} 4.170 + 4.171 +/** 4.172 + * Puts a key/value-pair into the map. 4.173 + * 4.174 + * @param map the map 4.175 + * @param key the key 4.176 + * @param value the value 4.177 + * @return 0 on success, non-zero value on failure 4.178 + */ 4.179 +__attribute__((__nonnull__)) 4.180 +static inline int cxMapPut( 4.181 + CxMap *map, 4.182 + CxDataPtr key, 4.183 + void const *value 4.184 +) { 4.185 + return map->cl->put(map, key, value); 4.186 +} 4.187 + 4.188 +/** 4.189 + * Retrieves a value by using a key. 4.190 + * 4.191 + * @param map the map 4.192 + * @param key the key 4.193 + * @return the value 4.194 + */ 4.195 +__attribute__((__nonnull__, __warn_unused_result__)) 4.196 +void *cxMapGet( 4.197 + CxMap const *map, 4.198 + CxDataPtr key 4.199 +) { 4.200 + return map->cl->get(map, key); 4.201 +} 4.202 + 4.203 +/** 4.204 + * Removes a key/value-pair from the map by using the key. 4.205 + * 4.206 + * @param map the map 4.207 + * @param key the key 4.208 + * @return the removed value 4.209 + */ 4.210 +__attribute__((__nonnull__, __warn_unused_result__)) 4.211 +void *cxMapRemove( 4.212 + CxMap *map, 4.213 + CxDataPtr key 4.214 +) { 4.215 + return map->cl->remove(map, key); 4.216 +} 4.217 + 4.218 +// TODO: set-like map operations (union, intersect, difference) 4.219 + 4.220 +/** 4.221 + * Creates a value iterator for a map. 4.222 + * 4.223 + * \note An iterator iterates over all elements successively. Therefore the order 4.224 + * highly depends on the map implementation and may change arbitrarily when the contents change. 4.225 + * 4.226 + * @param map the map to create the iterator for 4.227 + * @return an iterator for the currently stored values 4.228 + */ 4.229 +__attribute__((__nonnull__, __warn_unused_result__)) 4.230 +static inline CxIterator cxMapIteratorValues(CxMap const *map) { 4.231 + return map->cl->iterator_values(map); 4.232 +} 4.233 + 4.234 +/** 4.235 + * Creates a key iterator for a map. 4.236 + * 4.237 + * \note An iterator iterates over all elements successively. Therefore the order 4.238 + * highly depends on the map implementation and may change arbitrarily when the contents change. 4.239 + * 4.240 + * @param map the map to create the iterator for 4.241 + * @return an iterator for the currently stored keys 4.242 + */ 4.243 +__attribute__((__nonnull__, __warn_unused_result__)) 4.244 +static inline CxIterator cxMapIteratorKeys(CxMap const *map) { 4.245 + return map->cl->iterator_keys(map); 4.246 +} 4.247 + 4.248 +/** 4.249 + * Creates an iterator for a map. 4.250 + * 4.251 + * The values of the iterator are dynamically created key/value pairs of type CxMapEntry. 4.252 + * 4.253 + * \note An iterator iterates over all elements successively. Therefore the order 4.254 + * highly depends on the map implementation and may change arbitrarily when the contents change. 4.255 + * 4.256 + * @param map the map to create the iterator for 4.257 + * @return an iterator for the currently stored keys 4.258 + * @see cxMapIteratorKeys() 4.259 + * @see cxMapIteratorValues() 4.260 + */ 4.261 +__attribute__((__nonnull__, __warn_unused_result__)) 4.262 +static inline CxIterator cxMapIterator(CxMap const *map) { 4.263 + return map->cl->iterator(map); 4.264 +} 4.265 + 4.266 + 4.267 +#ifdef __cplusplus 4.268 +} 4.269 +#endif 4.270 + 4.271 +#endif // UCX_MAP_H 4.272 \ No newline at end of file
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/hash_map.c Wed May 18 16:26:32 2022 +0200 5.3 @@ -0,0 +1,105 @@ 5.4 +/* 5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 5.6 + * 5.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 5.8 + * 5.9 + * Redistribution and use in source and binary forms, with or without 5.10 + * modification, are permitted provided that the following conditions are met: 5.11 + * 5.12 + * 1. Redistributions of source code must retain the above copyright 5.13 + * notice, this list of conditions and the following disclaimer. 5.14 + * 5.15 + * 2. Redistributions in binary form must reproduce the above copyright 5.16 + * notice, this list of conditions and the following disclaimer in the 5.17 + * documentation and/or other materials provided with the distribution. 5.18 + * 5.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 5.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 5.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5.29 + * POSSIBILITY OF SUCH DAMAGE. 5.30 + */ 5.31 + 5.32 +#include <string.h> 5.33 +#include "cx/hash_map.h" 5.34 + 5.35 +/** 5.36 + * Computes a murmur hash-2. 5.37 + * 5.38 + * @param data the data to hash 5.39 + * @param len the length of the data 5.40 + * @return the murmur hash-2 of the data 5.41 + */ 5.42 +static unsigned cx_hash_map_murmur( 5.43 + unsigned char const *data, 5.44 + size_t len 5.45 +) { 5.46 + unsigned m = 0x5bd1e995; 5.47 + unsigned r = 24; 5.48 + unsigned h = 25 ^ len; 5.49 + unsigned i = 0; 5.50 + while (len >= 4) { 5.51 + unsigned k = data[i + 0] & 0xFF; 5.52 + k |= (data[i + 1] & 0xFF) << 8; 5.53 + k |= (data[i + 2] & 0xFF) << 16; 5.54 + k |= (data[i + 3] & 0xFF) << 24; 5.55 + 5.56 + k *= m; 5.57 + k ^= k >> r; 5.58 + k *= m; 5.59 + 5.60 + h *= m; 5.61 + h ^= k; 5.62 + 5.63 + i += 4; 5.64 + len -= 4; 5.65 + } 5.66 + 5.67 + switch (len) { 5.68 + case 3: 5.69 + h ^= (data[i + 2] & 0xFF) << 16; 5.70 + __attribute__((__fallthrough__)); 5.71 + case 2: 5.72 + h ^= (data[i + 1] & 0xFF) << 8; 5.73 + __attribute__((__fallthrough__)); 5.74 + case 1: 5.75 + h ^= (data[i + 0] & 0xFF); 5.76 + h *= m; 5.77 + __attribute__((__fallthrough__)); 5.78 + default: 5.79 + /* do nothing */; 5.80 + } 5.81 + 5.82 + h ^= h >> 13; 5.83 + h *= m; 5.84 + h ^= h >> 15; 5.85 + 5.86 + return h; 5.87 +} 5.88 + 5.89 + 5.90 +/** 5.91 + * Creates a hash map key based on the given data. 5.92 + * 5.93 + * This function implicitly computes the hash. 5.94 + * 5.95 + * @attention The data will be copied to the key structure. 5.96 + * 5.97 + * @param data the data for the key 5.98 + * @return the computed key 5.99 + */ 5.100 +static struct cx_hash_map_key_s cx_hash_map_key(CxDataPtr data) { 5.101 + unsigned char *target = malloc(data.len); 5.102 + memcpy(target, data.data, data.len); 5.103 + struct cx_hash_map_key_s key; 5.104 + key.data.data = target; 5.105 + key.data.len = data.len; 5.106 + key.hash = cx_hash_map_murmur(target, data.len); 5.107 + return key; 5.108 +}