blob: 22b6cf4d6a20851ea12b26d6e622d1d43fa7d2dd [file] [log] [blame]
/**
* @file hash_table_internal.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang hash table internal header
*
* Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_HASH_TABLE_INTERNAL_H_
#define LY_HASH_TABLE_INTERNAL_H_
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include "compat.h"
#include "hash_table.h"
/** reference value for 100% */
#define LYHT_HUNDRED_PERCENTAGE 100
/** when the table is at least this much percent full, it is enlarged (double the size) */
#define LYHT_ENLARGE_PERCENTAGE 75
/** only once the table is this much percent full, enable shrinking */
#define LYHT_FIRST_SHRINK_PERCENTAGE 50
/** when the table is less than this much percent full, it is shrunk (half the size) */
#define LYHT_SHRINK_PERCENTAGE 25
/** never shrink beyond this size */
#define LYHT_MIN_SIZE 8
/**
* @brief Generic hash table record.
*/
struct ly_ht_rec {
uint32_t hash; /* hash of the value */
uint32_t next; /* index of next collision */
unsigned char val[1]; /* arbitrary-size value */
} _PACKED;
/* real size, without taking the val[1] in account */
#define SIZEOF_LY_HT_REC (sizeof(struct ly_ht_rec) - 1)
struct ly_ht_hlist {
uint32_t first;
uint32_t last;
};
/**
* @brief (Very) generic hash table.
*
* This structure implements a hash table, providing fast accesses to stored
* values from their hash.
*
* The hash table structure contains 2 pointers to tables that are allocated
* at initialization:
* - a table of records: each record is composed of a struct ly_ht_rec header,
* followed by the user value. The header contains the hash value and a
* next index that can be used to chain records.
* - a table of list heads: each list head entry contains the index of the
* first record in the records table whose hash (modulo hash table size)
* is equal to the index of the list head entry. The other matching records
* are chained together.
*
* The unused records are chained in first_free_rec, which contains the index
* of the first unused record entry in the records table.
*
* The LYHT_NO_RECORD magic value is used when an index points to nothing.
*/
struct ly_ht {
uint32_t used; /* number of values stored in the hash table (filled records) */
uint32_t size; /* always holds 2^x == size (is power of 2), actually number of records allocated */
lyht_value_equal_cb val_equal; /* callback for testing value equivalence */
void *cb_data; /* user data callback arbitrary value */
uint16_t resize; /* 0 - resizing is disabled, *
* 1 - enlarging is enabled, *
* 2 - both shrinking and enlarging is enabled */
uint16_t rec_size; /* real size (in bytes) of one record for accessing recs array */
uint32_t first_free_rec; /* index of the first free record */
struct ly_ht_hlist *hlists; /* pointer to the hlists table */
unsigned char *recs; /* pointer to the hash table itself (array of struct ht_rec) */
};
/* index that points to nothing */
#define LYHT_NO_RECORD UINT32_MAX
/* get the record associated to */
static inline struct ly_ht_rec *
lyht_get_rec(unsigned char *recs, uint16_t rec_size, uint32_t idx)
{
return (struct ly_ht_rec *)&recs[idx * rec_size];
}
/* Iterate all records in a hlist */
#define LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec) \
for (rec_idx = ht->hlists[hlist_idx].first, \
rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx); \
rec_idx != LYHT_NO_RECORD; \
rec_idx = rec->next, \
rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx))
/* Iterate all records in the hash table */
#define LYHT_ITER_ALL_RECS(ht, hlist_idx, rec_idx, rec) \
for (hlist_idx = 0; hlist_idx < ht->size; hlist_idx++) \
LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec)
/**
* @brief Dictionary hash table record.
*/
struct ly_dict_rec {
char *value; /**< stored string */
uint32_t refcount; /**< reference count of the string */
};
/**
* @brief Dictionary for storing repeated strings.
*/
struct ly_dict {
struct ly_ht *hash_tab;
pthread_mutex_t lock;
};
/**
* @brief Initiate content (non-zero values) of the dictionary
*
* @param[in] dict Dictionary table to initiate
*/
void lydict_init(struct ly_dict *dict);
/**
* @brief Cleanup the dictionary content
*
* @param[in] dict Dictionary table to cleanup
*/
void lydict_clean(struct ly_dict *dict);
#endif /* LY_HASH_TABLE_INTERNAL_H_ */