libamxc  1.10.3
C Generic Data Containers
amxc_htable.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #include <amxc/amxc_hash.h>
59 #include <amxc/amxc_htable.h>
60 #include <amxc/amxc_macros.h>
61 
69  amxc_htable_it_t* const it) {
70  unsigned int index = 0;
71  amxc_array_it_t* ait = NULL;
72 
75  ait = amxc_array_get_at(&htable->table, index);
76  // insert item
77  if((ait != NULL) && (ait->data != NULL)) {
78  it->next = (amxc_htable_it_t*) ait->data;
79  }
81  it->ait = ait;
82  htable->items++;
83 }
84 
85 static int amxc_htable_grow(amxc_htable_t* const htable, size_t hint) {
86  int retval = -1;
87  size_t capacity = htable->table.items;
89  size_t start_bucket = htable->table.first_used;
90  size_t end_bucket = htable->table.last_used;
91 
92  htable->table.buffer = NULL;
93  htable->table.first_used = 0;
94  htable->table.last_used = 0;
95  htable->table.items = 0;
96  htable->items = 0;
97 
98  when_null(temp, exit);
99 
100  if(hint != 0) {
101  retval = amxc_array_grow(&htable->table, capacity + hint);
102  } else {
103  retval = amxc_array_grow(&htable->table, capacity > 1024 ? capacity + 1024 : 2 * capacity);
104  }
105  when_failed(retval, exit);
106 
107  for(size_t i = start_bucket; i <= end_bucket; i++) {
108  amxc_htable_it_t* hit = (amxc_htable_it_t*) temp[i].data;
109  amxc_htable_it_t* next = NULL;
110  if(hit == NULL) {
111  continue;
112  }
113  hit->ait = NULL;
114  next = hit->next;
115  hit->next = NULL;
117  while(next) {
118  hit = next;
119  hit->ait = NULL;
120  next = hit->next;
121  hit->next = NULL;
123  }
124  }
125  free(temp);
126 
127 exit:
128  return retval;
129 }
130 
132  amxc_htable_t* htable = (amxc_htable_t*) it->array;
133  amxc_htable_it_t* current = (amxc_htable_it_t*) it->data;
134 
135  while(current != NULL) {
136  amxc_htable_it_t* next = current->next;
137  char* key = current->key;
138  current->key = NULL;
139  amxc_htable_it_take(current);
140  if(htable->it_del != NULL) {
141  htable->it_del(key, current);
142  }
143  free(key);
144  current = next;
145  }
146 }
147 
148 int amxc_htable_new(amxc_htable_t** htable, const size_t reserve) {
149  int retval = -1;
150  when_null(htable, exit);
151 
152  *htable = (amxc_htable_t*) calloc(1, sizeof(amxc_htable_t));
153  when_null(*htable, exit);
154 
155  retval = amxc_htable_init(*htable, reserve);
156  if(retval == -1) {
157  free(*htable);
158  *htable = NULL;
159  }
160 
161 exit:
162  return retval;
163 }
164 
166  const char* key1 = (const char*) amxc_array_it_get_data(it1);
167  const char* key2 = (const char*) amxc_array_it_get_data(it2);
168  return strcmp(key1 == NULL? "":key1, key2 == NULL? "":key2);
169 }
170 
171 
173  when_null(htable, exit);
174  when_null(*htable, exit);
175 
176  (*htable)->it_del = func;
177  amxc_array_clean(&(*htable)->table, amxc_htable_it_delete_func);
178  free(*htable);
179  *htable = NULL;
180 
181 exit:
182  return;
183 }
184 
185 int amxc_htable_init(amxc_htable_t* const htable, const size_t reserve) {
186  int retval = -1;
187  when_null(htable, exit);
188 
189  htable->items = 0;
191 
192  when_failed(amxc_array_init(&htable->table, reserve != 0 ? reserve : 64), exit);
193 
194  retval = 0;
195 
196 exit:
197  return retval;
198 }
199 
201  when_null(htable, exit);
202 
203  htable->it_del = func;
205  htable->items = 0;
206 
207 exit:
208  return;
209 }
210 
213  when_null(htable, exit);
214 
215  if(func != NULL) {
216  htable->hfunc = func;
217  } else {
219  }
220 
221 exit:
222  return;
223 }
224 
225 unsigned int amxc_htable_key2index(const amxc_htable_t* const htable,
226  const char* const key) {
227  unsigned int hash = AMXC_HTABLE_RANGE;
228  when_null(htable, exit);
229  when_true(htable->table.items == 0, exit);
230 
231  hash = htable->hfunc(key, strlen(key)) % htable->table.items;
232 
233 exit:
234  return hash;
235 }
236 
238  const char* const key,
239  amxc_htable_it_t* const it) {
240  int retval = -1;
241 
242  when_null(htable, exit);
243  when_null(key, exit);
244  when_true(*key == 0, exit);
245  when_null(it, exit);
246 
247  // remove the iterator first
249  // no side effects here, strcmp does not modify the content of the string
250  // for performance reasons the pointer check is done first
251  if((it->key != NULL) && (strcmp(it->key, key) != 0)) {
252  free(it->key);
253  it->key = NULL;
254  }
255 
256  if((htable->table.items == 0) ||
257  (((htable->items + 1) * 100) / htable->table.items >= 75)) {
258  // time to grow the table
260  }
261 
262  // update htable iterator
263  if(it->key == NULL) {
264  size_t length = strlen(key);
265  it->key = (char*) calloc(length + 1, sizeof(char));
266  when_null(it->key, exit);
267  memcpy(it->key, key, length);
268  }
269 
271 
272  retval = 0;
273 
274 exit:
275  return retval;
276 }
277 
279  const char* const key) {
280  amxc_htable_it_t* it = NULL;
281  unsigned int index = 0;
282  amxc_array_it_t* ait = NULL;
283 
284  when_null(htable, exit);
285  when_null(key, exit);
286  when_true(*key == 0, exit);
287 
288  when_true(htable->table.items == 0, exit);
289 
290  index = amxc_htable_key2index(htable, key);
291  // the index is always in array bounderies.
292  // the following line is always returning a valid array iterator pointer
293  ait = amxc_array_get_at(&htable->table, index);
294 
295  it = ait == NULL? NULL:(amxc_htable_it_t*) ait->data;
296  while(it != NULL && strcmp(key, it->key) != 0) {
297  it = it->next;
298  }
299 
300 exit:
301  return it;
302 }
303 
305  const char* const key) {
307  if(it != NULL) {
309  }
310  return it;
311 }
312 
314  amxc_htable_it_t* it = NULL;
315  amxc_array_it_t* ait = NULL;
316  when_null(htable, exit);
317 
319  when_null(ait, exit);
320  it = (amxc_htable_it_t*) ait->data;
321 
322 exit:
323  return it;
324 }
325 
327  amxc_htable_it_t* it = NULL;
328  amxc_array_it_t* ait = NULL;
329  when_null(htable, exit);
330 
332  when_null(ait, exit);
333  it = (amxc_htable_it_t*) ait->data;
334 
335 exit:
336  return it;
337 }
338 
340  amxc_array_t* keys = NULL;
341  uint32_t size = 0;
342  uint32_t index = 0;
343  when_null(htable, exit);
344 
345  size = amxc_htable_size(htable);
346  when_true(size == 0, exit);
347 
348  amxc_array_new(&keys, size);
349  when_null(keys, exit);
350 
352  const char* key = amxc_htable_it_get_key(it);
353  amxc_array_set_data_at(keys, index, (void*) key);
354  index++;
355  }
356 
358 
359 exit:
360  return keys;
361 }
362 
363 int amxc_htable_move(amxc_htable_t* const dest, amxc_htable_t* const src) {
364  int retval = -1;
365  size_t needed_items = 0;
366  size_t needed_cap = 0;
367  size_t dest_cap = 0;
368 
369  when_null(dest, exit);
370  when_null(src, exit);
371 
372  needed_items = amxc_htable_size(src) + amxc_htable_size(dest);
373  needed_cap = ((needed_items + 1) * 100) / 75;
374  dest_cap = amxc_htable_capacity(dest);
375 
376  retval = 0;
377  if(dest_cap < needed_cap) {
378  retval = amxc_htable_grow(dest, needed_cap - dest_cap);
379  }
380  when_failed(retval, exit);
381 
382  amxc_htable_for_each(it, src) {
383  amxc_htable_insert_it(dest, it);
384  }
385 
386  retval = 0;
387 
388 exit:
389  return retval;
390 }
Ambiorix string hash functions header file.
static void amxc_htable_insert_it(amxc_htable_t *const htable, amxc_htable_it_t *const it)
Definition: amxc_htable.c:68
static int amxc_htable_cmp_keys(amxc_array_it_t *it1, amxc_array_it_t *it2)
Definition: amxc_htable.c:165
static void amxc_htable_it_delete_func(amxc_array_it_t *const it)
Definition: amxc_htable.c:131
static int amxc_htable_grow(amxc_htable_t *const htable, size_t hint)
Definition: amxc_htable.c:85
Ambiorix hash table API header file.
#define when_failed(x, l)
Definition: amxc_macros.h:142
#define when_true(x, l)
Definition: amxc_macros.h:134
#define when_null(x, l)
Definition: amxc_macros.h:126
int amxc_array_it_set_data(amxc_array_it_t *const it, void *data)
Sets the data pointer of an array iterator.
AMXC_INLINE void * amxc_array_it_get_data(const amxc_array_it_t *const it)
Gets the data pointer of array iterator.
Definition: amxc_array.h:729
amxc_array_it_t * amxc_array_get_last(const amxc_array_t *const array)
Gets the item iterator of the last used item in the array.
Definition: amxc_array.c:546
amxc_array_it_t * amxc_array_set_data_at(amxc_array_t *const array, const unsigned int index, void *data)
Sets data at the given index.
Definition: amxc_array.c:474
int amxc_array_init(amxc_array_t *const array, const size_t items)
Initializes an array.
Definition: amxc_array.c:231
amxc_array_it_t * amxc_array_get_at(const amxc_array_t *const array, const unsigned int index)
Gets the item iterator for the given index.
Definition: amxc_array.c:504
amxc_array_it_t * amxc_array_get_first(const amxc_array_t *const array)
Gets the item iterator of the first used item in the array.
Definition: amxc_array.c:517
int8_t amxc_array_new(amxc_array_t **array, const size_t items)
Allocates an array.
Definition: amxc_array.c:179
void amxc_array_clean(amxc_array_t *const array, amxc_array_it_delete_t func)
Removes all items from the array.
Definition: amxc_array.c:261
int amxc_array_sort(amxc_array_t *const array, amxc_array_it_cmp_t cmp)
Sorts the content of the array.
Definition: amxc_array.c:596
int amxc_array_grow(amxc_array_t *const array, const size_t items)
Expands the array.
Definition: amxc_array.c:280
unsigned int amxc_BKDR_hash(const char *str, const unsigned int len)
Calculate a hash from a string.
void amxc_htable_it_take(amxc_htable_it_t *const it)
Removes the iterator from the hash table.
AMXC_INLINE const char * amxc_htable_it_get_key(const amxc_htable_it_t *const it)
Gets the key from the iterator.
Definition: amxc_htable.h:672
int amxc_htable_init(amxc_htable_t *const htable, const size_t reserve)
Initializes a hash table.
Definition: amxc_htable.c:185
void amxc_htable_delete(amxc_htable_t **htable, amxc_htable_it_delete_t func)
Frees the previously allocated hash table.
Definition: amxc_htable.c:172
amxc_array_t * amxc_htable_get_sorted_keys(const amxc_htable_t *const htable)
Creates an array containing all keys of the hash table.
Definition: amxc_htable.c:339
amxc_htable_it_t * amxc_htable_get_first(const amxc_htable_t *const htable)
Gets the first item stored in the table.
Definition: amxc_htable.c:313
int amxc_htable_new(amxc_htable_t **htable, const size_t reserve)
Allocates a hash table.
Definition: amxc_htable.c:148
AMXC_INLINE size_t amxc_htable_size(const amxc_htable_t *const htable)
Calculates the size of the hash table.
Definition: amxc_htable.h:334
unsigned int(* amxc_htable_hash_func_t)(const char *key, const unsigned int len)
Definition of the hash function.
Definition: amxc_htable.h:158
int amxc_htable_move(amxc_htable_t *const dest, amxc_htable_t *const src)
Moves all items from one hash table to another hash table.
Definition: amxc_htable.c:363
unsigned int amxc_htable_key2index(const amxc_htable_t *const htable, const char *const key)
Converts a key into an index.
Definition: amxc_htable.c:225
amxc_htable_it_t * amxc_htable_take(amxc_htable_t *const htable, const char *const key)
Removes a hash table iterator from the hash table.
Definition: amxc_htable.c:304
void(* amxc_htable_it_delete_t)(const char *key, amxc_htable_it_t *it)
Definition of the hash table item delete function.
Definition: amxc_htable.h:168
amxc_htable_it_t * amxc_htable_get_last(const amxc_htable_t *const htable)
Gets the last item stored in the table.
Definition: amxc_htable.c:326
amxc_htable_it_t * amxc_htable_get(const amxc_htable_t *const htable, const char *const key)
Gets a hash table iterator from the hash table.
Definition: amxc_htable.c:278
AMXC_INLINE size_t amxc_htable_capacity(const amxc_htable_t *const htable)
Calculates the capacity of the hash table.
Definition: amxc_htable.h:351
int amxc_htable_insert(amxc_htable_t *const htable, const char *const key, amxc_htable_it_t *const it)
Inserts an item in the hash table.
Definition: amxc_htable.c:237
#define amxc_htable_for_each(it, htable)
Loops over items in the hash table.
Definition: amxc_htable.h:102
void amxc_htable_clean(amxc_htable_t *const htable, amxc_htable_it_delete_t func)
Removes all items from the hash table.
Definition: amxc_htable.c:200
#define AMXC_HTABLE_RANGE
Out of range indicator.
Definition: amxc_htable.h:129
void amxc_htable_set_hash_func(amxc_htable_t *const htable, amxc_htable_hash_func_t func)
Sets the hash function for the hash table.
Definition: amxc_htable.c:211
The array iterator structure.
Definition: amxc_array.h:174
The array structure.
Definition: amxc_array.h:162
size_t items
Definition: amxc_array.h:163
struct _amxc_array_it * buffer
Definition: amxc_array.h:166
size_t last_used
Definition: amxc_array.h:165
size_t first_used
Definition: amxc_array.h:164
The hash table iterator structure.
Definition: amxc_htable.h:138
amxc_array_it_t * ait
Definition: amxc_htable.h:139
amxc_htable_it_t * next
Definition: amxc_htable.h:141
The hash table structure.
Definition: amxc_htable.h:175
amxc_array_t table
Definition: amxc_htable.h:176
size_t items
Definition: amxc_htable.h:177
amxc_htable_hash_func_t hfunc
Definition: amxc_htable.h:178
amxc_htable_it_delete_t it_del
Definition: amxc_htable.h:179
char data[]
static amxc_htable_it_t it[2000]
static amxc_htable_t * htable
static amxc_llist_it_t it2
static amxc_llist_it_t it1