blob: 1921fca870af5e6b22ddf54509844b4e7228dbc6 [file] [log] [blame]
Michal Vaskoae130f52023-04-20 14:25:16 +02001/**
2 * @file hash_table_internal.h
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @author Michal Vasko <mvasko@cesnet.cz>
5 * @brief libyang hash table internal header
6 *
7 * Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
8 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
16#ifndef LY_HASH_TABLE_INTERNAL_H_
17#define LY_HASH_TABLE_INTERNAL_H_
18
19#include <pthread.h>
20#include <stddef.h>
21#include <stdint.h>
22
23#include "compat.h"
24#include "hash_table.h"
25
26/** reference value for 100% */
27#define LYHT_HUNDRED_PERCENTAGE 100
28
29/** when the table is at least this much percent full, it is enlarged (double the size) */
30#define LYHT_ENLARGE_PERCENTAGE 75
31
32/** only once the table is this much percent full, enable shrinking */
33#define LYHT_FIRST_SHRINK_PERCENTAGE 50
34
35/** when the table is less than this much percent full, it is shrunk (half the size) */
36#define LYHT_SHRINK_PERCENTAGE 25
37
Michal Vaskoae130f52023-04-20 14:25:16 +020038/** never shrink beyond this size */
39#define LYHT_MIN_SIZE 8
40
41/**
42 * @brief Generic hash table record.
43 */
44struct ly_ht_rec {
45 uint32_t hash; /* hash of the value */
Olivier Matz75c00192023-09-21 14:35:12 +020046 uint32_t next; /* index of next collision */
Michal Vaskoae130f52023-04-20 14:25:16 +020047 unsigned char val[1]; /* arbitrary-size value */
48} _PACKED;
49
Olivier Matz75c00192023-09-21 14:35:12 +020050/* real size, without taking the val[1] in account */
51#define SIZEOF_LY_HT_REC (sizeof(struct ly_ht_rec) - 1)
52
Michal Vaskoae130f52023-04-20 14:25:16 +020053/**
54 * @brief (Very) generic hash table.
55 *
Olivier Matz75c00192023-09-21 14:35:12 +020056 * This structure implements a hash table, providing fast accesses to stored
57 * values from their hash.
58 *
59 * The hash table structure contains 2 pointers to tables that are allocated
60 * at initialization:
61 * - a table of records: each record is composed of a struct ly_ht_rec header,
62 * followed by the user value. The header contains the hash value and a
63 * next index that can be used to chain records.
64 * - a table of list heads: each list head entry contains the index of the
65 * first record in the records table whose hash (modulo hash table size)
66 * is equal to the index of the list head entry. The other matching records
67 * are chained together.
68 *
69 * The unused records are chained in first_free_rec, which contains the index
70 * of the first unused record entry in the records table.
71 *
72 * The LYHT_NO_RECORD magic value is used when an index points to nothing.
Michal Vaskoae130f52023-04-20 14:25:16 +020073 */
74struct ly_ht {
75 uint32_t used; /* number of values stored in the hash table (filled records) */
76 uint32_t size; /* always holds 2^x == size (is power of 2), actually number of records allocated */
Michal Vaskoae130f52023-04-20 14:25:16 +020077 lyht_value_equal_cb val_equal; /* callback for testing value equivalence */
78 void *cb_data; /* user data callback arbitrary value */
79 uint16_t resize; /* 0 - resizing is disabled, *
80 * 1 - enlarging is enabled, *
81 * 2 - both shrinking and enlarging is enabled */
82 uint16_t rec_size; /* real size (in bytes) of one record for accessing recs array */
Olivier Matz75c00192023-09-21 14:35:12 +020083 uint32_t first_free_rec; /* index of the first free record */
84 uint32_t *hlists; /* pointer to the hlists table */
Michal Vaskoae130f52023-04-20 14:25:16 +020085 unsigned char *recs; /* pointer to the hash table itself (array of struct ht_rec) */
86};
87
Olivier Matz75c00192023-09-21 14:35:12 +020088/* index that points to nothing */
89#define LYHT_NO_RECORD UINT32_MAX
90
91/* get the record associated to */
92static inline struct ly_ht_rec *
93lyht_get_rec(unsigned char *recs, uint16_t rec_size, uint32_t idx)
94{
95 return (struct ly_ht_rec *)&recs[idx * rec_size];
96}
97
98/* Iterate all records in a hlist */
99#define LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec) \
100 for (rec_idx = ht->hlists[hlist_idx], \
101 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx); \
102 rec_idx != LYHT_NO_RECORD; \
103 rec_idx = rec->next, \
104 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx))
105
106/* Iterate all records in the hash table */
107#define LYHT_ITER_ALL_RECS(ht, hlist_idx, rec_idx, rec) \
108 for (hlist_idx = 0; hlist_idx < ht->size; hlist_idx++) \
109 LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec)
110
Michal Vaskoae130f52023-04-20 14:25:16 +0200111/**
112 * @brief Dictionary hash table record.
113 */
114struct ly_dict_rec {
115 char *value; /**< stored string */
116 uint32_t refcount; /**< reference count of the string */
117};
118
119/**
120 * @brief Dictionary for storing repeated strings.
121 */
122struct ly_dict {
123 struct ly_ht *hash_tab;
124 pthread_mutex_t lock;
125};
126
127/**
128 * @brief Initiate content (non-zero values) of the dictionary
129 *
130 * @param[in] dict Dictionary table to initiate
131 */
132void lydict_init(struct ly_dict *dict);
133
134/**
135 * @brief Cleanup the dictionary content
136 *
137 * @param[in] dict Dictionary table to cleanup
138 */
139void lydict_clean(struct ly_dict *dict);
140
141#endif /* LY_HASH_TABLE_INTERNAL_H_ */