blob: 2c7baa31fb45c1272e918a647b924acef0698a86 [file] [log] [blame]
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H
#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H
#include "src/core/ext/census/intrusive_hash_map_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/* intrusive_hash_map is a fast chained hash table. This hash map is faster than
* a dense hash map when the application calls insert and erase more often than
* find. When the workload is dominated by find() a dense hash map may be
* faster.
*
* intrusive_hash_map uses an intrusive header placed within a user defined
* struct. The header field IHM_key MUST be set to a valid value before
* insertion into the hash map or undefined behavior may occur. The header field
* IHM_hash_link MUST to be set to NULL initially.
*
* EXAMPLE USAGE:
*
* typedef struct string_item {
* INTRUSIVE_HASH_MAP_HEADER;
* // User data.
* char *str_buf;
* uint16_t len;
* } string_item;
*
* static string_item *make_string_item(uint64_t key, const char *buf,
* uint16_t len) {
* string_item *item = (string_item *)gpr_malloc(sizeof(string_item));
* item->IHM_key = key;
* item->IHM_hash_link = NULL;
* item->len = len;
* item->str_buf = (char *)malloc(len);
* memcpy(item->str_buf, buf, len);
* return item;
* }
*
* intrusive_hash_map hash_map;
* intrusive_hash_map_init(&hash_map, 4);
* string_item *new_item1 = make_string_item(10, "test1", 5);
* bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1);
*
* string_item *item1 =
* (string_item *)intrusive_hash_map_find(&hash_map, 10);
*/
/* Hash map item. Stores key and a pointer to the actual object. A user defined
* version of this can be passed in provided the first 2 entries (key and
* hash_link) are the same. These entries must be first in the user defined
* struct. Pointer to struct will need to be cast as (hm_item *) when passed to
* hash map. This allows it to be intrusive. */
typedef struct hm_item {
uint64_t key;
struct hm_item *hash_link;
/* Optional user defined data after this. */
} hm_item;
/* Macro provided for ease of use. This must be first in the user defined
* struct (i.e. uint64_t key and hm_item * must be the first two elements in
* that order). */
#define INTRUSIVE_HASH_MAP_HEADER \
uint64_t IHM_key; \
struct hm_item *IHM_hash_link
/* Index struct which acts as a pseudo-iterator within the hash map. */
typedef struct hm_index {
uint32_t bucket_index; // hash map bucket index.
hm_item *item; // Pointer to hm_item within the hash map.
} hm_index;
/* Returns true if two hm_indices point to the same object within the hash map
* and false otherwise. */
__inline bool hm_index_compare(const hm_index *A, const hm_index *B) {
return (A->item == B->item && A->bucket_index == B->bucket_index);
}
/*
* Helper functions for iterating over the hash map.
*/
/* On return idx will contain an invalid index which is always equal to
* hash_map->buckets.size_ */
void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx);
/* Iterates index to the next valid entry in the hash map and stores the
* index within idx. If end of table is reached, idx will contain the same
* values as if intrusive_hash_map_end() was called. */
void intrusive_hash_map_next(const intrusive_hash_map *hash_map, hm_index *idx);
/* On return, idx will contain the index of the first non-null entry in the hash
* map. If the hash map is empty, idx will contain the same values as if
* intrusive_hash_map_end() was called. */
void intrusive_hash_map_begin(const intrusive_hash_map *hash_map,
hm_index *idx);
/* Initialize intrusive hash map data structure. This must be called before
* the hash map can be used. The initial size of an intrusive hash map will be
* 2^initial_log2_map_size (valid range is [0, 31]). */
void intrusive_hash_map_init(intrusive_hash_map *hash_map,
uint32_t initial_log2_map_size);
/* Returns true if the hash map is empty and false otherwise. */
bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map);
/* Returns the number of elements currently in the hash map. */
size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map);
/* Find a hm_item within the hash map by key. Returns NULL if item was not
* found. */
hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map,
uint64_t key);
/* Erase the hm_item that corresponds with key. If the hm_item is found, return
* the pointer to the hm_item. Else returns NULL. */
hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key);
/* Attempts to insert a new hm_item into the hash map. If an element with the
* same key already exists, it will not insert the new item and return false.
* Otherwise, it will insert the new item and return true. */
bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item);
/* Clears entire contents of the hash map, but leaves internal data structure
* untouched. Second argument takes a function pointer to a function that will
* free the object designated by the user and pointed to by hash_map->value. */
void intrusive_hash_map_clear(intrusive_hash_map *hash_map,
void (*free_object)(void *));
/* Erase all contents of hash map and free the memory. Hash map is invalid
* after calling this function and cannot be used until it has been
* reinitialized (intrusive_hash_map_init()). This function takes a function
* pointer to a function that will free the object designated by the user and
* pointed to by hash_map->value. */
void intrusive_hash_map_free(intrusive_hash_map *hash_map,
void (*free_object)(void *));
#ifdef __cplusplus
}
#endif
#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H */