CAEN Utility  2.0.2
Utilities for CAEN projects
CAENMap.c
Go to the documentation of this file.
1 /******************************************************************************
2 *
3 * CAEN SpA - Software Division
4 * Via Vetraia, 11 - 55049 - Viareggio ITALY
5 * +39 0594 388 398 - www.caen.it
6 *
7 *******************************************************************************
8 *
9 * Copyright (C) 2014 rxi
10 *
11 * This file is part of the CAEN Utility.
12 *
13 * This file is distributed under the MIT License.
14 *
15 * SPDX-License-Identifier: MIT
16 *
17 ***************************************************************************/
25 #include <CAENMap.h>
26 
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include <CAENMultiplatform.h>
31 
32 
33 struct c_map_node_t {
34  char *key;
35  void *value;
36  uint32_t hash;
38 };
39 
40 
41 static uint32_t djb2a(const char *str) {
42  uint32_t hash = UINT32_C(5381);
43  char c;
44  while ((c = *str++) != '\0')
45  hash = (UINT32_C(33) * hash) ^ c;
46  return hash;
47 }
48 
49 
50 static c_map_node_t *map_newnode(const char *key, const void *value, size_t vsize) {
51  c_map_node_t *node = c_malloc(sizeof(*node));
52  if (node == NULL)
53  return NULL;
54 
55  node->key = c_strdup(key);
56  if (node->key == NULL) {
57  c_free(node);
58  return NULL;
59  }
60 
61  node->value = c_malloc(vsize);
62  if (node->value == NULL) {
63  c_free(node->key);
64  c_free(node);
65  return NULL;
66  }
67 
68  c_memcpy(node->value, value, vsize);
69 
70  node->hash = djb2a(key);
71 
72  node->next = NULL;
73 
74  return node;
75 }
76 
77 
78 static void map_deletenode(c_map_node_t *node) {
79  if (node == NULL)
80  return;
81  c_free(node->value);
82  c_free(node->key);
83  c_free(node);
84 }
85 
86 
87 static size_t map_bucketidx(const c_map_base_t *m, uint32_t hash) {
88  /* If the implementation is changed to allow a non-power-of-2 bucket count,
89  * the line below should be changed to use mod instead of AND */
90  return (size_t)hash & (m->nbuckets - 1);
91 }
92 
93 
94 static void map_addnode(c_map_base_t *m, c_map_node_t *node) {
95  size_t n = map_bucketidx(m, node->hash);
96  node->next = m->buckets[n];
97  m->buckets[n] = node;
98 }
99 
100 
101 static int32_t map_resize(c_map_base_t *m, size_t nbuckets) {
102  /* Chain all nodes together */
103  c_map_node_t *nodes = NULL;
104  while (m->nbuckets--) {
105  c_map_node_t *node = m->buckets[m->nbuckets];
106  while (node != NULL) {
107  c_map_node_t *next = node->next;
108  node->next = nodes;
109  nodes = node;
110  node = next;
111  }
112  }
113  /* Reset buckets */
114  c_map_node_t **buckets = c_realloc(m->buckets, sizeof(*m->buckets) * nbuckets);
115  if (buckets != NULL) {
116  m->buckets = buckets;
117  m->nbuckets = nbuckets;
118  }
119  if (m->buckets != NULL) {
120  c_zeromem(m->buckets, sizeof(*m->buckets) * m->nbuckets);
121  /* Re-add nodes to buckets */
122  c_map_node_t *node = nodes;
123  while (node != NULL) {
124  c_map_node_t *next = node->next;
125  map_addnode(m, node);
126  node = next;
127  }
128  }
129  /* Return error code if realloc() failed */
130  return (buckets == NULL) ? c_Utility_ErrorCode_Map : c_Utility_ErrorCode_Success;
131 }
132 
133 
134 static c_map_node_t **map_getref(const c_map_base_t *m, const char *key) {
135  if (m->nbuckets > 0) {
136  const uint32_t hash = djb2a(key);
137  c_map_node_t **next = &m->buckets[map_bucketidx(m, hash)];
138  while (*next != NULL) {
139  if ((*next)->hash == hash && !strcmp((*next)->key, key)) {
140  return next;
141  }
142  next = &(*next)->next;
143  }
144  }
145  return NULL;
146 }
147 
148 
149 int32_t _map_init(c_map_base_t *m, size_t nreserved) {
150  // Clear the memory.
151  m->buckets = NULL;
152  m->nbuckets = 0;
153  m->nnodes = 0;
154  m->initialized = TRUE;
155 
156  // Pre-initialize buckets array only if reserved is a power of 2.
157  // Anyway, it is reallocated automatically when needed.
158  if ((nreserved > 0) && !(nreserved & (nreserved - 1)))
159  return map_resize(m, nreserved);
160  else
162 }
163 
164 
166  if (m == NULL)
167  return;
168  if (!m->initialized)
169  return;
170 
171  while (m->nbuckets--) {
172  c_map_node_t *node = m->buckets[m->nbuckets];
173  while (node != NULL) {
174  c_map_node_t *next = node->next;
175  map_deletenode(node);
176  node = next;
177  }
178  }
179  c_free(m->buckets);
180  m->initialized = FALSE;
181 }
182 
183 
184 c_use_decl_annotations void *_map_get(const c_map_base_t *m, const char *key) {
185  if (m == NULL || key == NULL)
186  return NULL;
187  if (!m->initialized)
188  return NULL;
189 
190  c_map_node_t **next = map_getref(m, key);
191  return next ? (*next)->value : NULL;
192 }
193 
194 
195 int32_t _map_set(c_map_base_t *m, const char *key, const void *value, size_t vsize) {
196  if (m == NULL || key == NULL || value == NULL)
198  if (!m->initialized)
200 
201  /* Find & replace existing node */
202  c_map_node_t **next = map_getref(m, key);
203  if (next != NULL) {
204  c_memcpy((*next)->value, value, vsize);
206  }
207  /* Add new node */
208  c_map_node_t *node = map_newnode(key, value, vsize);
209  if (node == NULL)
210  goto fail;
211  if (m->nnodes >= m->nbuckets) {
212  size_t n = (m->nbuckets > 0) ? (m->nbuckets << 1) : 1U;
213  int32_t err = map_resize(m, n);
214  if (err != c_Utility_ErrorCode_Success)
215  goto fail;
216  }
217  map_addnode(m, node);
218  m->nnodes++;
220 fail:
221  map_deletenode(node);
223 }
224 
225 
226 void _map_remove(c_map_base_t *m, const char *key) {
227  if (m == NULL || key == NULL)
228  return;
229  if (!m->initialized)
230  return;
231 
232  c_map_node_t **next = map_getref(m, key);
233  if (next != NULL) {
234  c_map_node_t *node = *next;
235  *next = (*next)->next;
236  map_deletenode(node);
237  m->nnodes--;
238  }
239 }
240 
242  if (m == NULL)
243  return 0;
244  return m->nnodes;
245 }
246 
248  c_map_iter_t iter;
249  // we init bucketidx to max, so its increment will become from 0.
250  // see function _map_next() for details.
251  iter.bucketidx = SIZE_MAX;
252  iter.node = NULL;
253  return iter;
254 }
255 
257  if (m == NULL || iter == NULL)
258  return NULL;
259  if (!m->initialized)
260  return NULL;
261 
262  if (iter->node != NULL) {
263  iter->node = iter->node->next;
264  if (iter->node == NULL)
265  goto nextBucket;
266  } else {
267  nextBucket:
268  do {
269  if (++iter->bucketidx >= m->nbuckets)
270  return NULL;
271  iter->node = m->buckets[iter->bucketidx];
272  } while (iter->node == NULL);
273  }
274  return iter->node->key;
275 }
int32_t _map_set(c_map_base_t *m, const char *key, const void *value, size_t vsize)
Definition: CAENMap.c:195
Base type for maps.
Definition: CAENMapTypes.h:50
static void * c_memcpy(void *__restrict dest, const void *__restrict src, size_t size)
Wrapper to memcpy(dest, src, size), with check for NULL arguments.
void c_free(void *ptr)
size_t bucketidx
Definition: CAENMapTypes.h:59
static size_t map_bucketidx(const c_map_base_t *m, uint32_t hash)
Definition: CAENMap.c:87
c_map_iter_t _map_iter(void)
Definition: CAENMap.c:247
size_t nnodes
Definition: CAENMapTypes.h:53
const char * _map_next(const c_map_base_t *m, c_map_iter_t *iter)
Definition: CAENMap.c:256
void * value
Definition: CAENMap.c:35
void _map_deinit(c_map_base_t *m)
Definition: CAENMap.c:165
c_map_node_t * next
Definition: CAENMap.c:37
Hash table. Implementation from rxi&#39;s "map" project.
int32_t _map_init(c_map_base_t *m, size_t nreserved)
Definition: CAENMap.c:149
#define TRUE
Iterator.
Definition: CAENMapTypes.h:58
#define FALSE
static void map_addnode(c_map_base_t *m, c_map_node_t *node)
Definition: CAENMap.c:94
c_map_node_t ** buckets
Definition: CAENMapTypes.h:51
void * c_malloc(size_t size)
Generic wrappers to platform-dependent functions.
size_t nbuckets
Definition: CAENMapTypes.h:52
static c_map_node_t * map_newnode(const char *key, const void *value, size_t vsize)
Definition: CAENMap.c:50
static uint32_t djb2a(const char *str)
Definition: CAENMap.c:41
static void map_deletenode(c_map_node_t *node)
Definition: CAENMap.c:78
char * key
Definition: CAENMap.c:34
uint32_t hash
Definition: CAENMap.c:36
#define c_use_decl_annotations
Definition: CAENUtility.h:278
size_t _map_size(const c_map_base_t *m)
Definition: CAENMap.c:241
bool initialized
Definition: CAENMapTypes.h:54
c_map_node_t * node
Definition: CAENMapTypes.h:60
void _map_remove(c_map_base_t *m, const char *key)
Definition: CAENMap.c:226
void * c_realloc(void *ptr, size_t size)
char * c_strdup(const char *str)
Wrapper to strdup(str), with check for NULL arguments. To be freed with c_free(). ...
static c_map_node_t ** map_getref(const c_map_base_t *m, const char *key)
Definition: CAENMap.c:134
static void * c_zeromem(void *dest, size_t size)
Wrapper to memset(dest, 0, size), with check for NULL arguments.
static int32_t map_resize(c_map_base_t *m, size_t nbuckets)
Definition: CAENMap.c:101
void * _map_get(const c_map_base_t *m, const char *key)
Definition: CAENMap.c:184