blob: 22b6cf4d6a20851ea12b26d6e622d1d43fa7d2dd [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
Olivier Matz6a669c12023-09-28 12:07:12 +020053struct ly_ht_hlist {
54 uint32_t first;
55 uint32_t last;
56};
57
Michal Vaskoae130f52023-04-20 14:25:16 +020058/**
59 * @brief (Very) generic hash table.
60 *
Olivier Matz75c00192023-09-21 14:35:12 +020061 * This structure implements a hash table, providing fast accesses to stored
62 * values from their hash.
63 *
64 * The hash table structure contains 2 pointers to tables that are allocated
65 * at initialization:
66 * - a table of records: each record is composed of a struct ly_ht_rec header,
67 * followed by the user value. The header contains the hash value and a
68 * next index that can be used to chain records.
69 * - a table of list heads: each list head entry contains the index of the
70 * first record in the records table whose hash (modulo hash table size)
71 * is equal to the index of the list head entry. The other matching records
72 * are chained together.
73 *
74 * The unused records are chained in first_free_rec, which contains the index
75 * of the first unused record entry in the records table.
76 *
77 * The LYHT_NO_RECORD magic value is used when an index points to nothing.
Michal Vaskoae130f52023-04-20 14:25:16 +020078 */
79struct ly_ht {
80 uint32_t used; /* number of values stored in the hash table (filled records) */
81 uint32_t size; /* always holds 2^x == size (is power of 2), actually number of records allocated */
Michal Vaskoae130f52023-04-20 14:25:16 +020082 lyht_value_equal_cb val_equal; /* callback for testing value equivalence */
83 void *cb_data; /* user data callback arbitrary value */
84 uint16_t resize; /* 0 - resizing is disabled, *
85 * 1 - enlarging is enabled, *
86 * 2 - both shrinking and enlarging is enabled */
87 uint16_t rec_size; /* real size (in bytes) of one record for accessing recs array */
Olivier Matz75c00192023-09-21 14:35:12 +020088 uint32_t first_free_rec; /* index of the first free record */
Olivier Matz6a669c12023-09-28 12:07:12 +020089 struct ly_ht_hlist *hlists; /* pointer to the hlists table */
Michal Vaskoae130f52023-04-20 14:25:16 +020090 unsigned char *recs; /* pointer to the hash table itself (array of struct ht_rec) */
91};
92
Olivier Matz75c00192023-09-21 14:35:12 +020093/* index that points to nothing */
94#define LYHT_NO_RECORD UINT32_MAX
95
96/* get the record associated to */
97static inline struct ly_ht_rec *
98lyht_get_rec(unsigned char *recs, uint16_t rec_size, uint32_t idx)
99{
100 return (struct ly_ht_rec *)&recs[idx * rec_size];
101}
102
103/* Iterate all records in a hlist */
104#define LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec) \
Olivier Matz6a669c12023-09-28 12:07:12 +0200105 for (rec_idx = ht->hlists[hlist_idx].first, \
Olivier Matz75c00192023-09-21 14:35:12 +0200106 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx); \
107 rec_idx != LYHT_NO_RECORD; \
108 rec_idx = rec->next, \
109 rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx))
110
111/* Iterate all records in the hash table */
112#define LYHT_ITER_ALL_RECS(ht, hlist_idx, rec_idx, rec) \
113 for (hlist_idx = 0; hlist_idx < ht->size; hlist_idx++) \
114 LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec)
115
Michal Vaskoae130f52023-04-20 14:25:16 +0200116/**
117 * @brief Dictionary hash table record.
118 */
119struct ly_dict_rec {
120 char *value; /**< stored string */
121 uint32_t refcount; /**< reference count of the string */
122};
123
124/**
125 * @brief Dictionary for storing repeated strings.
126 */
127struct ly_dict {
128 struct ly_ht *hash_tab;
129 pthread_mutex_t lock;
130};
131
132/**
133 * @brief Initiate content (non-zero values) of the dictionary
134 *
135 * @param[in] dict Dictionary table to initiate
136 */
137void lydict_init(struct ly_dict *dict);
138
139/**
140 * @brief Cleanup the dictionary content
141 *
142 * @param[in] dict Dictionary table to cleanup
143 */
144void lydict_clean(struct ly_dict *dict);
145
146#endif /* LY_HASH_TABLE_INTERNAL_H_ */