summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/librdkafka-2.1.0/src/rdmap.h
blob: a79dcda06a8dde899d76732cf1b1babe52f8d1a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/*
 * librdkafka - The Apache Kafka C/C++ library
 *
 * Copyright (c) 2020 Magnus Edenhill
 * 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 OWNER 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 _RDMAP_H_
#define _RDMAP_H_

/**
 * @name Hash maps.
 *
 * Memory of key and value are allocated by the user but owned by the hash map
 * until elements are deleted or overwritten.
 *
 * The lower-case API provides a generic typeless (void *) hash map while
 * the upper-case API provides a strictly typed hash map implemented as macros
 * on top of the generic API.
 *
 * See rd_map_init(), et.al, for the generic API and RD_MAP_INITIALIZER()
 * for the typed API.
 *
 * @remark Not thread safe.
 */


/**
 * @struct Map element. This is the internal representation
 *         of the element and exposed to the user for iterating over the hash.
 */
typedef struct rd_map_elem_s {
        LIST_ENTRY(rd_map_elem_s) hlink; /**< Hash bucket link */
        LIST_ENTRY(rd_map_elem_s) link;  /**< Iterator link */
        unsigned int hash;               /**< Key hash value */
        const void *key;                 /**< Key (memory owned by map) */
        const void *value;               /**< Value (memory owned by map) */
} rd_map_elem_t;


/**
 * @struct Hash buckets (internal use).
 */
struct rd_map_buckets {
        LIST_HEAD(, rd_map_elem_s) * p; /**< Hash buckets array */
        int cnt;                        /**< Bucket count */
};


/**
 * @struct Hash map.
 */
typedef struct rd_map_s {
        struct rd_map_buckets rmap_buckets; /**< Hash buckets */
        int rmap_cnt;                       /**< Element count */

        LIST_HEAD(, rd_map_elem_s)
        rmap_iter; /**< Element list for iterating
                    *   over all elements. */

        int (*rmap_cmp)(const void *a, const void *b); /**< Key comparator */
        unsigned int (*rmap_hash)(const void *key);    /**< Key hash function */
        void (*rmap_destroy_key)(void *key);           /**< Optional key free */
        void (*rmap_destroy_value)(void *value); /**< Optional value free */

        void *rmap_opaque;
} rd_map_t;



/**
 * @brief Set/overwrite value in map.
 *
 * If an existing entry with the same key already exists its key and value
 * will be freed with the destroy_key and destroy_value functions
 * passed to rd_map_init().
 *
 * The map assumes memory ownership of both the \p key and \p value and will
 * use the destroy_key and destroy_value functions (if set) to free
 * the key and value memory when the map is destroyed or element removed.
 *
 * @returns the map element.
 */
rd_map_elem_t *rd_map_set(rd_map_t *rmap, void *key, void *value);


/**
 * @brief Look up \p key in the map and return its value, or NULL
 *        if \p key was not found.
 *
 * The returned memory is still owned by the map.
 */
void *rd_map_get(const rd_map_t *rmap, const void *key);


/**
 * @brief Delete \p key from the map, if it exists.
 *
 * The destroy_key and destroy_value functions (if set) will be used
 * to free the key and value memory.
 */
void rd_map_delete(rd_map_t *rmap, const void *key);


/** Key or Value Copy function signature. */
typedef void *(rd_map_copy_t)(const void *key_or_value);


/**
 * @brief Copy all elements from \p src to \p dst.
 *        \p dst must be initialized and compatible with \p src.
 *
 * @param dst Destination map to copy to.
 * @param src Source map to copy from.
 * @param key_copy Key copy callback. If NULL the \p dst key will just
 *                 reference the \p src key.
 * @param value_copy Value copy callback. If NULL the \p dst value will just
 *                   reference the \p src value.
 */
void rd_map_copy(rd_map_t *dst,
                 const rd_map_t *src,
                 rd_map_copy_t *key_copy,
                 rd_map_copy_t *value_copy);


/**
 * @returns the current number of elements in the map.
 */
size_t rd_map_cnt(const rd_map_t *rmap);

/**
 * @returns true if map is empty, else false.
 */
rd_bool_t rd_map_is_empty(const rd_map_t *rmap);


/**
 * @brief Iterate over all elements in the map.
 *
 * @warning The map MUST NOT be modified during the loop.
 *
 * @remark This is part of the untyped generic API.
 */
#define RD_MAP_FOREACH_ELEM(ELEM, RMAP)                                        \
        for (rd_map_iter_begin((RMAP), &(ELEM)); rd_map_iter(&(ELEM));         \
             rd_map_iter_next(&(ELEM)))


/**
 * @brief Begin iterating \p rmap, first element is set in \p *elem.
 */
void rd_map_iter_begin(const rd_map_t *rmap, const rd_map_elem_t **elem);

/**
 * @returns 1 if \p *elem is a valid iteration element, else 0.
 */
static RD_INLINE RD_UNUSED int rd_map_iter(const rd_map_elem_t **elem) {
        return *elem != NULL;
}

/**
 * @brief Advances the iteration to the next element.
 */
static RD_INLINE RD_UNUSED void rd_map_iter_next(const rd_map_elem_t **elem) {
        *elem = LIST_NEXT(*elem, link);
}


/**
 * @brief Initialize a map that is expected to hold \p expected_cnt elements.
 *
 * @param expected_cnt Expected number of elements in the map,
 *                     this is used to select a suitable bucket count.
 *                     Passing a value of 0 will set the bucket count
 *                     to a reasonable default.
 * @param cmp Key comparator that must return 0 if the two keys match.
 * @param hash Key hashing function that is used to map a key to a bucket.
 *             It must return an integer hash >= 0 of the key.
 * @param destroy_key (Optional) When an element is deleted or overwritten
 *                    this function will be used to free the key memory.
 * @param destroy_value (Optional) When an element is deleted or overwritten
 *                      this function will be used to free the value memory.
 *
 * Destroy the map with rd_map_destroy()
 *
 * @remarks The map is not thread-safe.
 */
void rd_map_init(rd_map_t *rmap,
                 size_t expected_cnt,
                 int (*cmp)(const void *a, const void *b),
                 unsigned int (*hash)(const void *key),
                 void (*destroy_key)(void *key),
                 void (*destroy_value)(void *value));


/**
 * @brief Internal use
 */
struct rd_map_buckets rd_map_alloc_buckets(size_t expected_cnt);


/**
 * @brief Empty the map and free all elements.
 */
void rd_map_clear(rd_map_t *rmap);


/**
 * @brief Free all elements in the map and free all memory associated
 *        with the map, but not the rd_map_t itself.
 *
 * The map is unusable after this call but can be re-initialized using
 * rd_map_init().
 *
 * @sa rd_map_clear()
 */
void rd_map_destroy(rd_map_t *rmap);


/**
 * @brief String comparator for (const char *) keys.
 */
int rd_map_str_cmp(const void *a, const void *b);


/**
 * @brief String hash function (djb2) for (const char *) keys.
 */
unsigned int rd_map_str_hash(const void *a);



/**
 * @name Typed hash maps.
 *
 * Typed hash maps provides a type-safe layer on top of the standard hash maps.
 */

/**
 * @brief Define a typed map type which can later be used with
 *        RD_MAP_INITIALIZER() and typed RD_MAP_*() API.
 */
#define RD_MAP_TYPE(KEY_TYPE, VALUE_TYPE)                                      \
        struct {                                                               \
                rd_map_t rmap;                                                 \
                KEY_TYPE key;                                                  \
                VALUE_TYPE value;                                              \
                const rd_map_elem_t *elem;                                     \
        }

/**
 * @brief Initialize a typed hash map. The left hand side variable must be
 *        a typed hash map defined by RD_MAP_TYPE().
 *
 * The typed hash map is a macro layer on top of the rd_map_t implementation
 * that provides type safety.
 * The methods are the same as the underlying implementation but in all caps
 * (to indicate their macro use), e.g., RD_MAP_SET() is the typed version
 * of rd_map_set().
 *
 * @param EXPECTED_CNT Expected number of elements in hash.
 * @param KEY_TYPE The type of the hash key.
 * @param VALUE_TYPE The type of the hash value.
 * @param CMP Comparator function for the key.
 * @param HASH Hash function for the key.
 * @param DESTROY_KEY Destructor for the key type.
 * @param DESTROY_VALUE Destructor for the value type.
 *
 * @sa rd_map_init()
 */
#define RD_MAP_INITIALIZER(EXPECTED_CNT, CMP, HASH, DESTROY_KEY,                \
                           DESTROY_VALUE)                                       \
        {                                                                       \
                .rmap = {                                                       \
                        .rmap_buckets     = rd_map_alloc_buckets(EXPECTED_CNT), \
                        .rmap_cmp         = CMP,                                \
                        .rmap_hash        = HASH,                               \
                        .rmap_destroy_key = DESTROY_KEY,                        \
                        .rmap_destroy_value = DESTROY_VALUE                     \
                }                                                               \
        }


/**
 * @brief Initialize a locally-defined typed hash map.
 *        This hash map can only be used in the current scope/function
 *        as its type is private to this initializement.
 *
 * @param RMAP Hash map variable name.
 *
 * For the other parameters, see RD_MAP_INITIALIZER().
 *
 * @sa RD_MAP_INITIALIZER()
 */
#define RD_MAP_LOCAL_INITIALIZER(RMAP, EXPECTED_CNT, KEY_TYPE, VALUE_TYPE,     \
                                 CMP, HASH, DESTROY_KEY, DESTROY_VALUE)        \
        struct {                                                               \
                rd_map_t rmap;                                                 \
                KEY_TYPE key;                                                  \
                VALUE_TYPE value;                                              \
                const rd_map_elem_t *elem;                                     \
        } RMAP = RD_MAP_INITIALIZER(EXPECTED_CNT, CMP, HASH, DESTROY_KEY,      \
                                    DESTROY_VALUE)


/**
 * @brief Initialize typed map \p RMAP.
 *
 * @sa rd_map_init()
 */
#define RD_MAP_INIT(RMAP, EXPECTED_CNT, CMP, HASH, DESTROY_KEY, DESTROY_VALUE) \
        rd_map_init(&(RMAP)->rmap, EXPECTED_CNT, CMP, HASH, DESTROY_KEY,       \
                    DESTROY_VALUE)


/**
 * @brief Allocate and initialize a typed map.
 */


/**
 * @brief Typed hash map: Set key/value in map.
 *
 * @sa rd_map_set()
 */
#define RD_MAP_SET(RMAP, KEY, VALUE)                                           \
        ((RMAP)->key = KEY, (RMAP)->value = VALUE,                             \
         rd_map_set(&(RMAP)->rmap, (void *)(RMAP)->key,                        \
                    (void *)(RMAP)->value))

/**
 * @brief Typed hash map: Get value for key.
 *
 * @sa rd_map_get()
 */
#define RD_MAP_GET(RMAP, KEY)                                                  \
        ((RMAP)->key   = (KEY),                                                \
         (RMAP)->value = rd_map_get(&(RMAP)->rmap, (RMAP)->key),               \
         (RMAP)->value)



/**
 * @brief Get value for key. If key does not exist in map a new
 *        entry is added using the DEFAULT_CODE.
 */
#define RD_MAP_GET_OR_SET(RMAP, KEY, DEFAULT_CODE)                             \
        (RD_MAP_GET(RMAP, KEY)                                                 \
             ? (RMAP)->value                                                   \
             : (RD_MAP_SET(RMAP, (RMAP)->key, DEFAULT_CODE), (RMAP)->value))


/**
 * @brief Typed hash map: Delete element by key.
 *
 * The destroy_key and destroy_value functions (if set) will be used
 * to free the key and value memory.
 *
 * @sa rd_map_delete()
 */
#define RD_MAP_DELETE(RMAP, KEY)                                               \
        ((RMAP)->key = (KEY), rd_map_delete(&(RMAP)->rmap, (RMAP)->key))


/**
 * @brief Copy all elements from \p SRC to \p DST.
 *        \p DST must be initialized and compatible with \p SRC.
 *
 * @param DST Destination map to copy to.
 * @param SRC Source map to copy from.
 * @param KEY_COPY Key copy callback. If NULL the \p DST key will just
 *                 reference the \p SRC key.
 * @param VALUE_COPY Value copy callback. If NULL the \p DST value will just
 *                   reference the \p SRC value.
 */
#define RD_MAP_COPY(DST, SRC, KEY_COPY, VALUE_COPY)                            \
        do {                                                                   \
                if ((DST) != (SRC)) /*implicit type-check*/                    \
                        rd_map_copy(&(DST)->rmap, &(SRC)->rmap, KEY_COPY,      \
                                    VALUE_COPY);                               \
        } while (0)


/**
 * @brief Empty the map and free all elements.
 *
 * @sa rd_map_clear()
 */
#define RD_MAP_CLEAR(RMAP) rd_map_clear(&(RMAP)->rmap)


/**
 * @brief Typed hash map: Destroy hash map.
 *
 * @sa rd_map_destroy()
 */
#define RD_MAP_DESTROY(RMAP) rd_map_destroy(&(RMAP)->rmap)


/**
 * @brief Typed hash map: Destroy and free the hash map.
 *
 * @sa rd_map_destroy()
 */
#define RD_MAP_DESTROY_AND_FREE(RMAP)                                          \
        do {                                                                   \
                rd_map_destroy(&(RMAP)->rmap);                                 \
                rd_free(RMAP);                                                 \
        } while (0)


/**
 * @brief Typed hash map: Iterate over all elements in the map.
 *
 * @warning The current or previous elements may be removed, but the next
 *          element after the current one MUST NOT be modified during the loop.
 *
 * @warning RD_MAP_FOREACH() only supports one simultaneous invocation,
 *          that is, special care must be taken not to call FOREACH() from
 *          within a FOREACH() or FOREACH_KEY() loop on the same map.
 *          This is due to how RMAP->elem is used as the iterator.
 *          This restriction is unfortunately not enforced at build or run time.
 *
 * @remark The \p RMAP may not be const.
 */
#define RD_MAP_FOREACH(K, V, RMAP)                                             \
        for (rd_map_iter_begin(&(RMAP)->rmap, &(RMAP)->elem), (K) = NULL,      \
                                                              (V) = NULL;      \
             rd_map_iter(&(RMAP)->elem) &&                                     \
             ((RMAP)->key = (void *)(RMAP)->elem->key, (K) = (RMAP)->key,      \
             (RMAP)->value = (void *)(RMAP)->elem->value, (V) = (RMAP)->value, \
             rd_map_iter_next(&(RMAP)->elem), rd_true);)


/**
 * @brief Typed hash map: Iterate over all keys in the map.
 *
 * @warning The current or previous elements may be removed, but the next
 *          element after the current one MUST NOT be modified during the loop.
 *
 * @warning RD_MAP_FOREACH_KEY() only supports one simultaneous invocation,
 *          that is, special care must be taken not to call FOREACH_KEY() from
 *          within a FOREACH() or FOREACH_KEY() loop on the same map.
 *          This is due to how RMAP->elem is used as the iterator.
 *          This restriction is unfortunately not enforced at build or run time.
 *
 * @remark The \p RMAP may not be const.
 */
#define RD_MAP_FOREACH_KEY(K, RMAP)                                            \
        for (rd_map_iter_begin(&(RMAP)->rmap, &(RMAP)->elem), (K) = NULL;      \
             rd_map_iter(&(RMAP)->elem) &&                                     \
             ((RMAP)->key = (void *)(RMAP)->elem->key, (K) = (RMAP)->key,      \
             rd_map_iter_next(&(RMAP)->elem), rd_true);)


/**
 * @returns the number of elements in the map.
 */
#define RD_MAP_CNT(RMAP) rd_map_cnt(&(RMAP)->rmap)

/**
 * @returns true if map is empty, else false.
 */
#define RD_MAP_IS_EMPTY(RMAP) rd_map_is_empty(&(RMAP)->rmap)

#endif /* _RDMAP_H_ */