/src/fluent-bit/lib/librdkafka-2.10.1/src/rdmap.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * librdkafka - The Apache Kafka C/C++ library |
3 | | * |
4 | | * Copyright (c) 2020-2022, Magnus Edenhill |
5 | | * 2023, Confluent Inc. |
6 | | * All rights reserved. |
7 | | * |
8 | | * Redistribution and use in source and binary forms, with or without |
9 | | * modification, are permitted provided that the following conditions are met: |
10 | | * |
11 | | * 1. Redistributions of source code must retain the above copyright notice, |
12 | | * this list of conditions and the following disclaimer. |
13 | | * 2. Redistributions in binary form must reproduce the above copyright notice, |
14 | | * this list of conditions and the following disclaimer in the documentation |
15 | | * and/or other materials provided with the distribution. |
16 | | * |
17 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
18 | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
21 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
22 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
23 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
24 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
25 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
26 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 | | * POSSIBILITY OF SUCH DAMAGE. |
28 | | */ |
29 | | |
30 | | #ifndef _RDMAP_H_ |
31 | | #define _RDMAP_H_ |
32 | | |
33 | | /** |
34 | | * @name Hash maps. |
35 | | * |
36 | | * Memory of key and value are allocated by the user but owned by the hash map |
37 | | * until elements are deleted or overwritten. |
38 | | * |
39 | | * The lower-case API provides a generic typeless (void *) hash map while |
40 | | * the upper-case API provides a strictly typed hash map implemented as macros |
41 | | * on top of the generic API. |
42 | | * |
43 | | * See rd_map_init(), et.al, for the generic API and RD_MAP_INITIALIZER() |
44 | | * for the typed API. |
45 | | * |
46 | | * @remark Not thread safe. |
47 | | */ |
48 | | |
49 | | |
50 | | /** |
51 | | * @struct Map element. This is the internal representation |
52 | | * of the element and exposed to the user for iterating over the hash. |
53 | | */ |
54 | | typedef struct rd_map_elem_s { |
55 | | LIST_ENTRY(rd_map_elem_s) hlink; /**< Hash bucket link */ |
56 | | LIST_ENTRY(rd_map_elem_s) link; /**< Iterator link */ |
57 | | unsigned int hash; /**< Key hash value */ |
58 | | const void *key; /**< Key (memory owned by map) */ |
59 | | const void *value; /**< Value (memory owned by map) */ |
60 | | } rd_map_elem_t; |
61 | | |
62 | | |
63 | | /** |
64 | | * @struct Hash buckets (internal use). |
65 | | */ |
66 | | struct rd_map_buckets { |
67 | | LIST_HEAD(, rd_map_elem_s) * p; /**< Hash buckets array */ |
68 | | int cnt; /**< Bucket count */ |
69 | | }; |
70 | | |
71 | | |
72 | | /** |
73 | | * @struct Hash map. |
74 | | */ |
75 | | typedef struct rd_map_s { |
76 | | struct rd_map_buckets rmap_buckets; /**< Hash buckets */ |
77 | | int rmap_cnt; /**< Element count */ |
78 | | |
79 | | LIST_HEAD(, rd_map_elem_s) |
80 | | rmap_iter; /**< Element list for iterating |
81 | | * over all elements. */ |
82 | | |
83 | | int (*rmap_cmp)(const void *a, const void *b); /**< Key comparator */ |
84 | | unsigned int (*rmap_hash)(const void *key); /**< Key hash function */ |
85 | | void (*rmap_destroy_key)(void *key); /**< Optional key free */ |
86 | | void (*rmap_destroy_value)(void *value); /**< Optional value free */ |
87 | | |
88 | | void *rmap_opaque; |
89 | | } rd_map_t; |
90 | | |
91 | | |
92 | | |
93 | | /** |
94 | | * @brief Set/overwrite value in map. |
95 | | * |
96 | | * If an existing entry with the same key already exists its key and value |
97 | | * will be freed with the destroy_key and destroy_value functions |
98 | | * passed to rd_map_init(). |
99 | | * |
100 | | * The map assumes memory ownership of both the \p key and \p value and will |
101 | | * use the destroy_key and destroy_value functions (if set) to free |
102 | | * the key and value memory when the map is destroyed or element removed. |
103 | | * |
104 | | * @returns the map element. |
105 | | */ |
106 | | rd_map_elem_t *rd_map_set(rd_map_t *rmap, void *key, void *value); |
107 | | |
108 | | |
109 | | /** |
110 | | * @brief Look up \p key in the map and return its value, or NULL |
111 | | * if \p key was not found. |
112 | | * |
113 | | * The returned memory is still owned by the map. |
114 | | */ |
115 | | void *rd_map_get(const rd_map_t *rmap, const void *key); |
116 | | |
117 | | |
118 | | /** |
119 | | * @brief Delete \p key from the map, if it exists. |
120 | | * |
121 | | * The destroy_key and destroy_value functions (if set) will be used |
122 | | * to free the key and value memory. |
123 | | */ |
124 | | void rd_map_delete(rd_map_t *rmap, const void *key); |
125 | | |
126 | | |
127 | | /** Key or Value Copy function signature. */ |
128 | | typedef void *(rd_map_copy_t)(const void *key_or_value); |
129 | | |
130 | | |
131 | | /** |
132 | | * @brief Copy all elements from \p src to \p dst. |
133 | | * \p dst must be initialized and compatible with \p src. |
134 | | * |
135 | | * @param dst Destination map to copy to. |
136 | | * @param src Source map to copy from. |
137 | | * @param key_copy Key copy callback. If NULL the \p dst key will just |
138 | | * reference the \p src key. |
139 | | * @param value_copy Value copy callback. If NULL the \p dst value will just |
140 | | * reference the \p src value. |
141 | | */ |
142 | | void rd_map_copy(rd_map_t *dst, |
143 | | const rd_map_t *src, |
144 | | rd_map_copy_t *key_copy, |
145 | | rd_map_copy_t *value_copy); |
146 | | |
147 | | |
148 | | /** |
149 | | * @returns the current number of elements in the map. |
150 | | */ |
151 | | size_t rd_map_cnt(const rd_map_t *rmap); |
152 | | |
153 | | /** |
154 | | * @returns true if map is empty, else false. |
155 | | */ |
156 | | rd_bool_t rd_map_is_empty(const rd_map_t *rmap); |
157 | | |
158 | | |
159 | | /** |
160 | | * @brief Iterate over all elements in the map. |
161 | | * |
162 | | * @warning The map MUST NOT be modified during the loop. |
163 | | * |
164 | | * @remark This is part of the untyped generic API. |
165 | | */ |
166 | | #define RD_MAP_FOREACH_ELEM(ELEM, RMAP) \ |
167 | 0 | for (rd_map_iter_begin((RMAP), &(ELEM)); rd_map_iter(&(ELEM)); \ |
168 | 0 | rd_map_iter_next(&(ELEM))) |
169 | | |
170 | | |
171 | | /** |
172 | | * @brief Begin iterating \p rmap, first element is set in \p *elem. |
173 | | */ |
174 | | void rd_map_iter_begin(const rd_map_t *rmap, const rd_map_elem_t **elem); |
175 | | |
176 | | /** |
177 | | * @returns 1 if \p *elem is a valid iteration element, else 0. |
178 | | */ |
179 | 0 | static RD_INLINE RD_UNUSED int rd_map_iter(const rd_map_elem_t **elem) { |
180 | 0 | return *elem != NULL; |
181 | 0 | } Unexecuted instantiation: rdkafka.c:rd_map_iter Unexecuted instantiation: rdkafka_assignor.c:rd_map_iter Unexecuted instantiation: rdkafka_broker.c:rd_map_iter Unexecuted instantiation: rdkafka_buf.c:rd_map_iter Unexecuted instantiation: rdkafka_cgrp.c:rd_map_iter Unexecuted instantiation: rdkafka_conf.c:rd_map_iter Unexecuted instantiation: rdkafka_feature.c:rd_map_iter Unexecuted instantiation: rdkafka_metadata.c:rd_map_iter Unexecuted instantiation: rdkafka_metadata_cache.c:rd_map_iter Unexecuted instantiation: rdkafka_msg.c:rd_map_iter Unexecuted instantiation: rdkafka_offset.c:rd_map_iter Unexecuted instantiation: rdkafka_op.c:rd_map_iter Unexecuted instantiation: rdkafka_partition.c:rd_map_iter Unexecuted instantiation: rdkafka_pattern.c:rd_map_iter Unexecuted instantiation: rdkafka_queue.c:rd_map_iter Unexecuted instantiation: rdkafka_range_assignor.c:rd_map_iter Unexecuted instantiation: rdkafka_request.c:rd_map_iter Unexecuted instantiation: rdkafka_roundrobin_assignor.c:rd_map_iter Unexecuted instantiation: rdkafka_sasl.c:rd_map_iter Unexecuted instantiation: rdkafka_sasl_plain.c:rd_map_iter Unexecuted instantiation: rdkafka_sticky_assignor.c:rd_map_iter Unexecuted instantiation: rdkafka_subscription.c:rd_map_iter Unexecuted instantiation: rdkafka_assignment.c:rd_map_iter Unexecuted instantiation: rdkafka_timer.c:rd_map_iter Unexecuted instantiation: rdkafka_topic.c:rd_map_iter Unexecuted instantiation: rdkafka_transport.c:rd_map_iter Unexecuted instantiation: rdkafka_interceptor.c:rd_map_iter Unexecuted instantiation: rdkafka_header.c:rd_map_iter Unexecuted instantiation: rdkafka_admin.c:rd_map_iter Unexecuted instantiation: rdkafka_aux.c:rd_map_iter Unexecuted instantiation: rdkafka_background.c:rd_map_iter Unexecuted instantiation: rdkafka_idempotence.c:rd_map_iter Unexecuted instantiation: rdkafka_txnmgr.c:rd_map_iter Unexecuted instantiation: rdkafka_cert.c:rd_map_iter Unexecuted instantiation: rdkafka_coord.c:rd_map_iter Unexecuted instantiation: rdkafka_mock.c:rd_map_iter Unexecuted instantiation: rdkafka_mock_handlers.c:rd_map_iter Unexecuted instantiation: rdkafka_mock_cgrp.c:rd_map_iter Unexecuted instantiation: rdkafka_error.c:rd_map_iter Unexecuted instantiation: rdkafka_fetcher.c:rd_map_iter Unexecuted instantiation: rdkafka_telemetry.c:rd_map_iter Unexecuted instantiation: rdkafka_telemetry_decode.c:rd_map_iter Unexecuted instantiation: rdkafka_telemetry_encode.c:rd_map_iter Unexecuted instantiation: rdunittest.c:rd_map_iter Unexecuted instantiation: rdmap.c:rd_map_iter Unexecuted instantiation: snappy.c:rd_map_iter Unexecuted instantiation: rdkafka_ssl.c:rd_map_iter Unexecuted instantiation: rdkafka_plugin.c:rd_map_iter Unexecuted instantiation: rdavl.c:rd_map_iter Unexecuted instantiation: rdkafka_event.c:rd_map_iter Unexecuted instantiation: rdkafka_lz4.c:rd_map_iter Unexecuted instantiation: rdkafka_msgset_reader.c:rd_map_iter Unexecuted instantiation: rdkafka_msgset_writer.c:rd_map_iter Unexecuted instantiation: rdlog.c:rd_map_iter |
182 | | |
183 | | /** |
184 | | * @brief Advances the iteration to the next element. |
185 | | */ |
186 | 0 | static RD_INLINE RD_UNUSED void rd_map_iter_next(const rd_map_elem_t **elem) { |
187 | 0 | *elem = LIST_NEXT(*elem, link); |
188 | 0 | } Unexecuted instantiation: rdkafka.c:rd_map_iter_next Unexecuted instantiation: rdkafka_assignor.c:rd_map_iter_next Unexecuted instantiation: rdkafka_broker.c:rd_map_iter_next Unexecuted instantiation: rdkafka_buf.c:rd_map_iter_next Unexecuted instantiation: rdkafka_cgrp.c:rd_map_iter_next Unexecuted instantiation: rdkafka_conf.c:rd_map_iter_next Unexecuted instantiation: rdkafka_feature.c:rd_map_iter_next Unexecuted instantiation: rdkafka_metadata.c:rd_map_iter_next Unexecuted instantiation: rdkafka_metadata_cache.c:rd_map_iter_next Unexecuted instantiation: rdkafka_msg.c:rd_map_iter_next Unexecuted instantiation: rdkafka_offset.c:rd_map_iter_next Unexecuted instantiation: rdkafka_op.c:rd_map_iter_next Unexecuted instantiation: rdkafka_partition.c:rd_map_iter_next Unexecuted instantiation: rdkafka_pattern.c:rd_map_iter_next Unexecuted instantiation: rdkafka_queue.c:rd_map_iter_next Unexecuted instantiation: rdkafka_range_assignor.c:rd_map_iter_next Unexecuted instantiation: rdkafka_request.c:rd_map_iter_next Unexecuted instantiation: rdkafka_roundrobin_assignor.c:rd_map_iter_next Unexecuted instantiation: rdkafka_sasl.c:rd_map_iter_next Unexecuted instantiation: rdkafka_sasl_plain.c:rd_map_iter_next Unexecuted instantiation: rdkafka_sticky_assignor.c:rd_map_iter_next Unexecuted instantiation: rdkafka_subscription.c:rd_map_iter_next Unexecuted instantiation: rdkafka_assignment.c:rd_map_iter_next Unexecuted instantiation: rdkafka_timer.c:rd_map_iter_next Unexecuted instantiation: rdkafka_topic.c:rd_map_iter_next Unexecuted instantiation: rdkafka_transport.c:rd_map_iter_next Unexecuted instantiation: rdkafka_interceptor.c:rd_map_iter_next Unexecuted instantiation: rdkafka_header.c:rd_map_iter_next Unexecuted instantiation: rdkafka_admin.c:rd_map_iter_next Unexecuted instantiation: rdkafka_aux.c:rd_map_iter_next Unexecuted instantiation: rdkafka_background.c:rd_map_iter_next Unexecuted instantiation: rdkafka_idempotence.c:rd_map_iter_next Unexecuted instantiation: rdkafka_txnmgr.c:rd_map_iter_next Unexecuted instantiation: rdkafka_cert.c:rd_map_iter_next Unexecuted instantiation: rdkafka_coord.c:rd_map_iter_next Unexecuted instantiation: rdkafka_mock.c:rd_map_iter_next Unexecuted instantiation: rdkafka_mock_handlers.c:rd_map_iter_next Unexecuted instantiation: rdkafka_mock_cgrp.c:rd_map_iter_next Unexecuted instantiation: rdkafka_error.c:rd_map_iter_next Unexecuted instantiation: rdkafka_fetcher.c:rd_map_iter_next Unexecuted instantiation: rdkafka_telemetry.c:rd_map_iter_next Unexecuted instantiation: rdkafka_telemetry_decode.c:rd_map_iter_next Unexecuted instantiation: rdkafka_telemetry_encode.c:rd_map_iter_next Unexecuted instantiation: rdunittest.c:rd_map_iter_next Unexecuted instantiation: rdmap.c:rd_map_iter_next Unexecuted instantiation: snappy.c:rd_map_iter_next Unexecuted instantiation: rdkafka_ssl.c:rd_map_iter_next Unexecuted instantiation: rdkafka_plugin.c:rd_map_iter_next Unexecuted instantiation: rdavl.c:rd_map_iter_next Unexecuted instantiation: rdkafka_event.c:rd_map_iter_next Unexecuted instantiation: rdkafka_lz4.c:rd_map_iter_next Unexecuted instantiation: rdkafka_msgset_reader.c:rd_map_iter_next Unexecuted instantiation: rdkafka_msgset_writer.c:rd_map_iter_next Unexecuted instantiation: rdlog.c:rd_map_iter_next |
189 | | |
190 | | |
191 | | /** |
192 | | * @brief Initialize a map that is expected to hold \p expected_cnt elements. |
193 | | * |
194 | | * @param expected_cnt Expected number of elements in the map, |
195 | | * this is used to select a suitable bucket count. |
196 | | * Passing a value of 0 will set the bucket count |
197 | | * to a reasonable default. |
198 | | * @param cmp Key comparator that must return 0 if the two keys match. |
199 | | * @param hash Key hashing function that is used to map a key to a bucket. |
200 | | * It must return an integer hash >= 0 of the key. |
201 | | * @param destroy_key (Optional) When an element is deleted or overwritten |
202 | | * this function will be used to free the key memory. |
203 | | * @param destroy_value (Optional) When an element is deleted or overwritten |
204 | | * this function will be used to free the value memory. |
205 | | * |
206 | | * Destroy the map with rd_map_destroy() |
207 | | * |
208 | | * @remarks The map is not thread-safe. |
209 | | */ |
210 | | void rd_map_init(rd_map_t *rmap, |
211 | | size_t expected_cnt, |
212 | | int (*cmp)(const void *a, const void *b), |
213 | | unsigned int (*hash)(const void *key), |
214 | | void (*destroy_key)(void *key), |
215 | | void (*destroy_value)(void *value)); |
216 | | |
217 | | |
218 | | /** |
219 | | * @brief Internal use |
220 | | */ |
221 | | struct rd_map_buckets rd_map_alloc_buckets(size_t expected_cnt); |
222 | | |
223 | | |
224 | | /** |
225 | | * @brief Empty the map and free all elements. |
226 | | */ |
227 | | void rd_map_clear(rd_map_t *rmap); |
228 | | |
229 | | |
230 | | /** |
231 | | * @brief Free all elements in the map and free all memory associated |
232 | | * with the map, but not the rd_map_t itself. |
233 | | * |
234 | | * The map is unusable after this call but can be re-initialized using |
235 | | * rd_map_init(). |
236 | | * |
237 | | * @sa rd_map_clear() |
238 | | */ |
239 | | void rd_map_destroy(rd_map_t *rmap); |
240 | | |
241 | | |
242 | | /** |
243 | | * @brief String comparator for (const char *) keys. |
244 | | */ |
245 | | int rd_map_str_cmp(const void *a, const void *b); |
246 | | |
247 | | |
248 | | /** |
249 | | * @brief String hash function (djb2) for (const char *) keys. |
250 | | */ |
251 | | unsigned int rd_map_str_hash(const void *a); |
252 | | |
253 | | /** |
254 | | * @brief Bytes hash function (djb2). |
255 | | */ |
256 | | unsigned int rd_bytes_hash(unsigned char *bytes, size_t len); |
257 | | |
258 | | |
259 | | /** |
260 | | * @name Typed hash maps. |
261 | | * |
262 | | * Typed hash maps provides a type-safe layer on top of the standard hash maps. |
263 | | */ |
264 | | |
265 | | /** |
266 | | * @brief Define a typed map type which can later be used with |
267 | | * RD_MAP_INITIALIZER() and typed RD_MAP_*() API. |
268 | | */ |
269 | | #define RD_MAP_TYPE(KEY_TYPE, VALUE_TYPE) \ |
270 | | struct { \ |
271 | | rd_map_t rmap; \ |
272 | | KEY_TYPE key; \ |
273 | | VALUE_TYPE value; \ |
274 | | const rd_map_elem_t *elem; \ |
275 | | } |
276 | | |
277 | | /** |
278 | | * @brief Initialize a typed hash map. The left hand side variable must be |
279 | | * a typed hash map defined by RD_MAP_TYPE(). |
280 | | * |
281 | | * The typed hash map is a macro layer on top of the rd_map_t implementation |
282 | | * that provides type safety. |
283 | | * The methods are the same as the underlying implementation but in all caps |
284 | | * (to indicate their macro use), e.g., RD_MAP_SET() is the typed version |
285 | | * of rd_map_set(). |
286 | | * |
287 | | * @param EXPECTED_CNT Expected number of elements in hash. |
288 | | * @param KEY_TYPE The type of the hash key. |
289 | | * @param VALUE_TYPE The type of the hash value. |
290 | | * @param CMP Comparator function for the key. |
291 | | * @param HASH Hash function for the key. |
292 | | * @param DESTROY_KEY Destructor for the key type. |
293 | | * @param DESTROY_VALUE Destructor for the value type. |
294 | | * |
295 | | * @sa rd_map_init() |
296 | | */ |
297 | | #define RD_MAP_INITIALIZER(EXPECTED_CNT, CMP, HASH, DESTROY_KEY, \ |
298 | | DESTROY_VALUE) \ |
299 | 0 | { \ |
300 | 0 | .rmap = { \ |
301 | 0 | .rmap_buckets = rd_map_alloc_buckets(EXPECTED_CNT), \ |
302 | 0 | .rmap_cmp = CMP, \ |
303 | 0 | .rmap_hash = HASH, \ |
304 | 0 | .rmap_destroy_key = DESTROY_KEY, \ |
305 | 0 | .rmap_destroy_value = DESTROY_VALUE \ |
306 | 0 | } \ |
307 | 0 | } |
308 | | |
309 | | |
310 | | /** |
311 | | * @brief Initialize a locally-defined typed hash map. |
312 | | * This hash map can only be used in the current scope/function |
313 | | * as its type is private to this initializement. |
314 | | * |
315 | | * @param RMAP Hash map variable name. |
316 | | * |
317 | | * For the other parameters, see RD_MAP_INITIALIZER(). |
318 | | * |
319 | | * @sa RD_MAP_INITIALIZER() |
320 | | */ |
321 | | #define RD_MAP_LOCAL_INITIALIZER(RMAP, EXPECTED_CNT, KEY_TYPE, VALUE_TYPE, \ |
322 | | CMP, HASH, DESTROY_KEY, DESTROY_VALUE) \ |
323 | 0 | struct { \ |
324 | 0 | rd_map_t rmap; \ |
325 | 0 | KEY_TYPE key; \ |
326 | 0 | VALUE_TYPE value; \ |
327 | 0 | const rd_map_elem_t *elem; \ |
328 | 0 | } RMAP = RD_MAP_INITIALIZER(EXPECTED_CNT, CMP, HASH, DESTROY_KEY, \ |
329 | 0 | DESTROY_VALUE) |
330 | | |
331 | | |
332 | | /** |
333 | | * @brief Initialize typed map \p RMAP. |
334 | | * |
335 | | * @sa rd_map_init() |
336 | | */ |
337 | | #define RD_MAP_INIT(RMAP, EXPECTED_CNT, CMP, HASH, DESTROY_KEY, DESTROY_VALUE) \ |
338 | 0 | rd_map_init(&(RMAP)->rmap, EXPECTED_CNT, CMP, HASH, DESTROY_KEY, \ |
339 | 0 | DESTROY_VALUE) |
340 | | |
341 | | |
342 | | /** |
343 | | * @brief Allocate and initialize a typed map. |
344 | | */ |
345 | | |
346 | | |
347 | | /** |
348 | | * @brief Typed hash map: Set key/value in map. |
349 | | * |
350 | | * @sa rd_map_set() |
351 | | */ |
352 | | #define RD_MAP_SET(RMAP, KEY, VALUE) \ |
353 | 0 | ((RMAP)->key = KEY, (RMAP)->value = VALUE, \ |
354 | 0 | rd_map_set(&(RMAP)->rmap, (void *)(RMAP)->key, \ |
355 | 0 | (void *)(RMAP)->value)) |
356 | | |
357 | | /** |
358 | | * @brief Typed hash map: Get value for key. |
359 | | * |
360 | | * @sa rd_map_get() |
361 | | */ |
362 | | #define RD_MAP_GET(RMAP, KEY) \ |
363 | 0 | ((RMAP)->key = (KEY), \ |
364 | 0 | (RMAP)->value = rd_map_get(&(RMAP)->rmap, (RMAP)->key), \ |
365 | 0 | (RMAP)->value) |
366 | | |
367 | | |
368 | | |
369 | | /** |
370 | | * @brief Get value for key. If key does not exist in map a new |
371 | | * entry is added using the DEFAULT_CODE. |
372 | | */ |
373 | | #define RD_MAP_GET_OR_SET(RMAP, KEY, DEFAULT_CODE) \ |
374 | 0 | (RD_MAP_GET(RMAP, KEY) \ |
375 | 0 | ? (RMAP)->value \ |
376 | 0 | : (RD_MAP_SET(RMAP, (RMAP)->key, DEFAULT_CODE), (RMAP)->value)) |
377 | | |
378 | | |
379 | | /** |
380 | | * @brief Typed hash map: Delete element by key. |
381 | | * |
382 | | * The destroy_key and destroy_value functions (if set) will be used |
383 | | * to free the key and value memory. |
384 | | * |
385 | | * @sa rd_map_delete() |
386 | | */ |
387 | | #define RD_MAP_DELETE(RMAP, KEY) \ |
388 | 0 | ((RMAP)->key = (KEY), rd_map_delete(&(RMAP)->rmap, (RMAP)->key)) |
389 | | |
390 | | |
391 | | /** |
392 | | * @brief Copy all elements from \p SRC to \p DST. |
393 | | * \p DST must be initialized and compatible with \p SRC. |
394 | | * |
395 | | * @param DST Destination map to copy to. |
396 | | * @param SRC Source map to copy from. |
397 | | * @param KEY_COPY Key copy callback. If NULL the \p DST key will just |
398 | | * reference the \p SRC key. |
399 | | * @param VALUE_COPY Value copy callback. If NULL the \p DST value will just |
400 | | * reference the \p SRC value. |
401 | | */ |
402 | | #define RD_MAP_COPY(DST, SRC, KEY_COPY, VALUE_COPY) \ |
403 | 0 | do { \ |
404 | 0 | if ((DST) != (SRC)) /*implicit type-check*/ \ |
405 | 0 | rd_map_copy(&(DST)->rmap, &(SRC)->rmap, KEY_COPY, \ |
406 | 0 | VALUE_COPY); \ |
407 | 0 | } while (0) |
408 | | |
409 | | |
410 | | /** |
411 | | * @brief Empty the map and free all elements. |
412 | | * |
413 | | * @sa rd_map_clear() |
414 | | */ |
415 | 0 | #define RD_MAP_CLEAR(RMAP) rd_map_clear(&(RMAP)->rmap) |
416 | | |
417 | | |
418 | | /** |
419 | | * @brief Typed hash map: Destroy hash map. |
420 | | * |
421 | | * @sa rd_map_destroy() |
422 | | */ |
423 | 0 | #define RD_MAP_DESTROY(RMAP) rd_map_destroy(&(RMAP)->rmap) |
424 | | |
425 | | |
426 | | /** |
427 | | * @brief Typed hash map: Destroy and free the hash map. |
428 | | * |
429 | | * @sa rd_map_destroy() |
430 | | */ |
431 | | #define RD_MAP_DESTROY_AND_FREE(RMAP) \ |
432 | 0 | do { \ |
433 | 0 | rd_map_destroy(&(RMAP)->rmap); \ |
434 | 0 | rd_free(RMAP); \ |
435 | 0 | } while (0) |
436 | | |
437 | | |
438 | | /** |
439 | | * @brief Typed hash map: Iterate over all elements in the map. |
440 | | * |
441 | | * @warning The current or previous elements may be removed, but the next |
442 | | * element after the current one MUST NOT be modified during the loop. |
443 | | * |
444 | | * @warning RD_MAP_FOREACH() only supports one simultaneous invocation, |
445 | | * that is, special care must be taken not to call FOREACH() from |
446 | | * within a FOREACH() or FOREACH_KEY() loop on the same map. |
447 | | * This is due to how RMAP->elem is used as the iterator. |
448 | | * This restriction is unfortunately not enforced at build or run time. |
449 | | * |
450 | | * @remark The \p RMAP may not be const. |
451 | | */ |
452 | | #define RD_MAP_FOREACH(K, V, RMAP) \ |
453 | 0 | for (rd_map_iter_begin(&(RMAP)->rmap, &(RMAP)->elem), (K) = NULL, \ |
454 | 0 | (V) = NULL; \ |
455 | 0 | rd_map_iter(&(RMAP)->elem) && \ |
456 | 0 | ((RMAP)->key = (void *)(RMAP)->elem->key, (K) = (RMAP)->key, \ |
457 | 0 | (RMAP)->value = (void *)(RMAP)->elem->value, (V) = (RMAP)->value, \ |
458 | 0 | rd_map_iter_next(&(RMAP)->elem), rd_true);) |
459 | | |
460 | | |
461 | | /** |
462 | | * @brief Typed hash map: Iterate over all keys in the map. |
463 | | * |
464 | | * @warning The current or previous elements may be removed, but the next |
465 | | * element after the current one MUST NOT be modified during the loop. |
466 | | * |
467 | | * @warning RD_MAP_FOREACH_KEY() only supports one simultaneous invocation, |
468 | | * that is, special care must be taken not to call FOREACH_KEY() from |
469 | | * within a FOREACH() or FOREACH_KEY() loop on the same map. |
470 | | * This is due to how RMAP->elem is used as the iterator. |
471 | | * This restriction is unfortunately not enforced at build or run time. |
472 | | * |
473 | | * @remark The \p RMAP may not be const. |
474 | | */ |
475 | | #define RD_MAP_FOREACH_KEY(K, RMAP) \ |
476 | 0 | for (rd_map_iter_begin(&(RMAP)->rmap, &(RMAP)->elem), (K) = NULL; \ |
477 | 0 | rd_map_iter(&(RMAP)->elem) && \ |
478 | 0 | ((RMAP)->key = (void *)(RMAP)->elem->key, (K) = (RMAP)->key, \ |
479 | 0 | rd_map_iter_next(&(RMAP)->elem), rd_true);) |
480 | | |
481 | | |
482 | | /** |
483 | | * @returns the number of elements in the map. |
484 | | */ |
485 | 0 | #define RD_MAP_CNT(RMAP) rd_map_cnt(&(RMAP)->rmap) |
486 | | |
487 | | /** |
488 | | * @returns true if map is empty, else false. |
489 | | */ |
490 | 0 | #define RD_MAP_IS_EMPTY(RMAP) rd_map_is_empty(&(RMAP)->rmap) |
491 | | |
492 | | #endif /* _RDMAP_H_ */ |