Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief The Order Preserving Minimal Perfect Hash Map.
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 :
10 : #include <kdbassert.h>
11 : #include <kdbconfig.h>
12 : #include <kdbhelper.h>
13 : #include <kdblogger.h>
14 : #include <kdbmacros.h>
15 : #include <kdbopmphm.h>
16 : #include <kdbrand.h>
17 :
18 : #include <string.h>
19 :
20 : static int hasCycle (Opmphm * opmphm, OpmphmGraph * graph, size_t n);
21 :
22 : /**
23 : * @brief Looks up a element in the OPMPHM.
24 : *
25 : * @param opmphm the OPMPHM
26 : * @param n the number of elements
27 : * @param name the name of the element
28 : *
29 : * @retval size_t the order of the element.
30 : */
31 1327300 : size_t opmphmLookup (Opmphm * opmphm, size_t n, const void * name)
32 : {
33 1327300 : ELEKTRA_NOT_NULL (opmphm);
34 1327300 : ELEKTRA_ASSERT (opmphm->rUniPar > 0 && opmphm->componentSize > 0, "passed opmphm is uninitialized");
35 1327300 : ELEKTRA_ASSERT (opmphm->graph != NULL, "passed opmphm is empty");
36 1327300 : ELEKTRA_ASSERT (name != NULL, "passed name is a Null Pointer");
37 1327300 : ELEKTRA_ASSERT (n > 0, "n is 0");
38 1327300 : ELEKTRA_ASSERT (n <= KDB_OPMPHM_MAX_N, "n > KDB_OPMPHM_MAX");
39 520 : size_t ret = 0;
40 : #ifndef OPMPHM_TEST
41 520 : size_t nameLength = strlen (name);
42 : #endif
43 7964274 : for (uint8_t r = 0; r < opmphm->rUniPar; ++r)
44 : {
45 : #ifndef OPMPHM_TEST
46 3074 : uint32_t hash = opmphmHashfunction (name, nameLength, opmphm->hashFunctionSeeds[r]) % opmphm->componentSize;
47 : #else
48 7960680 : uint32_t hash = ((uint32_t *) name)[r];
49 : #endif
50 7963754 : ret += opmphm->graph[r * opmphm->componentSize + hash];
51 : }
52 1327300 : return ret % n;
53 : }
54 :
55 : /**
56 : * @brief Assigns the vertices of the r-uniform r-partite hypergraph.
57 : *
58 : * Allocs the memory for the final OPMPHM `Opmphm->graph`.
59 : * Uses the remove sequence `OpmphmGraph->removeSequence`, generated during cycle check, to assign
60 : * each vertex. Either with `OpmphmEdge->order` or the default order, default is the order
61 : * of `OpmphmInit->data`.
62 : *
63 : * @param opmphm the OPMPHM
64 : * @param graph the OpmphmGraph
65 : * @param n the number of elements
66 : * @param defaultOrder boolean flag
67 : *
68 : * @retval 0 on success
69 : * @retval -1 on memory error
70 : */
71 9748 : int opmphmAssignment (Opmphm * opmphm, OpmphmGraph * graph, size_t n, int defaultOrder)
72 : {
73 9748 : ELEKTRA_NOT_NULL (opmphm);
74 9748 : ELEKTRA_ASSERT (opmphm->rUniPar > 0 && opmphm->componentSize > 0, "passed opmphm is uninitialized");
75 9748 : ELEKTRA_NOT_NULL (graph);
76 9748 : ELEKTRA_ASSERT (graph->removeIndex == n, "graph contains a cycle");
77 9748 : ELEKTRA_ASSERT (n > 0, "n is 0");
78 9748 : ELEKTRA_ASSERT (n <= KDB_OPMPHM_MAX_N, "n > KDB_OPMPHM_MAX");
79 9748 : size_t size = opmphm->componentSize * opmphm->rUniPar * sizeof (uint32_t);
80 9748 : opmphm->graph = elektraCalloc (size);
81 9748 : if (!opmphm->graph)
82 : {
83 : return -1;
84 : }
85 9748 : opmphm->size = size;
86 : // opmphm->graph[i] == 0 iff vertex i is not assigned
87 : // write 0 value with n, since n mod n = 0
88 9748 : size_t i = n;
89 : do
90 : {
91 1328440 : --i;
92 1328440 : uint8_t assignableVertex = opmphm->rUniPar;
93 1328440 : size_t assignedValue = 0;
94 : // assign edge e
95 1328440 : uint32_t e = graph->removeSequence[i];
96 9295040 : for (uint8_t r = 0; r < opmphm->rUniPar; ++r)
97 : {
98 : // go through all vertices from e
99 7966600 : size_t v = r * opmphm->componentSize + graph->edges[e].vertices[r];
100 7966600 : if (!opmphm->graph[v])
101 : {
102 7963569 : if (assignableVertex == opmphm->rUniPar)
103 : {
104 : // found the first assignableVertex
105 : assignableVertex = r;
106 : }
107 : else
108 : {
109 : // already found an assignableVertex
110 : // assign it != 0
111 6635129 : opmphm->graph[v] = 1;
112 6635129 : assignedValue += 1;
113 : }
114 : }
115 : else
116 : {
117 3031 : assignedValue += opmphm->graph[v];
118 : }
119 : }
120 1328440 : ELEKTRA_ASSERT (assignableVertex != opmphm->rUniPar, "no assignableVertex, can not happen");
121 : // assing the assignableVertex
122 1328440 : size_t v = assignableVertex * opmphm->componentSize + graph->edges[e].vertices[assignableVertex];
123 : size_t order;
124 1328440 : if (defaultOrder)
125 : {
126 : order = e;
127 : }
128 : else
129 : {
130 663390 : order = graph->edges[e].order;
131 : }
132 1328440 : if (assignedValue >= n)
133 : {
134 1025 : assignedValue = assignedValue % n;
135 : }
136 1328440 : if (assignedValue <= order)
137 : {
138 1279908 : opmphm->graph[v] = (order - assignedValue) ? (order - assignedValue) : n;
139 : }
140 : else
141 : {
142 48532 : opmphm->graph[v] = (n - assignedValue + order) ? (n - assignedValue + order) : n;
143 : }
144 1328440 : } while (i);
145 : return 0;
146 : }
147 :
148 : /**
149 : * @brief Maps the elements to edges in the r-uniform r-partite hypergraph.
150 : *
151 : * Sets the seeds for the opmphmHashfunctions, `OpmphmInit->initSeed` will be changed.
152 : * Inserts each element as edge in the r-uniform r-partite hypergraph and checks if the graph contains a cycle.
153 : * If there are cycles the `graph` will be cleaned
154 : *
155 : * @param opmphm the OPMPHM
156 : * @param graph the OpmphmGraph
157 : * @param init the OpmphmInit
158 : * @param n the number of elements
159 : *
160 : * @retval 0 on success
161 : * @retval -1 mapping not possible
162 : */
163 34066 : int opmphmMapping (Opmphm * opmphm, OpmphmGraph * graph, OpmphmInit * init, size_t n)
164 : {
165 34066 : ELEKTRA_NOT_NULL (opmphm);
166 34066 : ELEKTRA_ASSERT (opmphm->rUniPar > 0 && opmphm->componentSize > 0, "passed opmphm is uninitialized");
167 34066 : ELEKTRA_NOT_NULL (graph);
168 34066 : ELEKTRA_NOT_NULL (init);
169 34066 : ELEKTRA_ASSERT (init->getName != NULL, "passed init->getString is a Null Pointer");
170 34066 : ELEKTRA_ASSERT (init->data != NULL, "passed init->data is a Null Pointer");
171 34066 : ELEKTRA_ASSERT (n > 0, "n is 0");
172 34066 : ELEKTRA_ASSERT (n <= KDB_OPMPHM_MAX_N, "n > KDB_OPMPHM_MAX");
173 : // set seeds
174 204386 : for (uint8_t r = 0; r < opmphm->rUniPar; ++r)
175 : {
176 204386 : elektraRand (&(init->initSeed));
177 204386 : opmphm->hashFunctionSeeds[r] = init->initSeed;
178 : }
179 14669338 : for (size_t i = 0; i < n; ++i)
180 : {
181 : #ifndef OPMPHM_TEST
182 1660 : const char * name = init->getName (init->data[i]);
183 : #endif
184 101378888 : for (uint8_t r = 0; r < opmphm->rUniPar; ++r)
185 : {
186 : #ifndef OPMPHM_TEST
187 : // set edge.h[]
188 11840 : graph->edges[i].vertices[r] =
189 5920 : opmphmHashfunction (name, strlen (name), opmphm->hashFunctionSeeds[r]) % opmphm->componentSize;
190 : #endif
191 : // add edge to graph
192 : // set edge.nextEdge[r]
193 101377228 : size_t v = r * opmphm->componentSize + graph->edges[i].vertices[r];
194 101377228 : graph->edges[i].nextEdge[r] = graph->vertices[v].firstEdge;
195 : // set vertex.firstEdge
196 101377228 : graph->vertices[v].firstEdge = i;
197 : // increment degree
198 101377228 : ++graph->vertices[v].degree;
199 : }
200 : }
201 34066 : if (hasCycle (opmphm, graph, n))
202 : {
203 : // reset graph vertices
204 24318 : opmphmGraphClear (opmphm, graph);
205 24318 : return -1;
206 : }
207 : else
208 : {
209 : return 0;
210 : }
211 : }
212 :
213 : /**
214 : * @brief Recursive function used by hasCycle
215 : *
216 : * `v` is a degree 1 vertex with edge `e`. The edge `e` will be removed completely from the graph and
217 : * inserted in the `OpmphmGraph->removeSequence`.
218 : * For all vertices connected through `e` with degree 1 the function will be called again.
219 : *
220 : * @param opmphm the OPMPHM
221 : * @param graph the OpmphmGraph
222 : * @param v a vertex with degree 1
223 : */
224 2637402 : static void peel_off (Opmphm * opmphm, OpmphmGraph * graph, size_t v)
225 : {
226 2637402 : uint32_t e = graph->vertices[v].firstEdge;
227 : // add it to graph->removeSequence
228 2637402 : graph->removeSequence[graph->removeIndex] = e;
229 2637402 : ++graph->removeIndex;
230 : // remove edge e from graph
231 18451286 : for (uint8_t r = 0; r < opmphm->rUniPar; ++r)
232 : {
233 : // w is adjacent to v through e
234 15813884 : size_t w = r * opmphm->componentSize + graph->edges[e].vertices[r];
235 : // remove e from w
236 15813884 : uint32_t * j = &(graph->vertices[w].firstEdge);
237 15813884 : for (; *j != e; j = &(graph->edges[*j].nextEdge[r]))
238 : ;
239 15813884 : *j = graph->edges[*j].nextEdge[r];
240 : // decrease degree
241 15813884 : --graph->vertices[w].degree;
242 : }
243 : // all vertices adjacent to v through e
244 15813884 : for (uint8_t r = 0; r < opmphm->rUniPar; ++r)
245 : {
246 15813884 : size_t w = r * opmphm->componentSize + graph->edges[e].vertices[r];
247 : // if degree 1, go on
248 15813884 : if (graph->vertices[w].degree == 1)
249 : {
250 1434 : peel_off (opmphm, graph, w);
251 : }
252 : }
253 2637402 : }
254 :
255 : /**
256 : * @brief Checks if an OpmphmGraph is Acyclic
257 : *
258 : * Removes edges that have a degree 1 vertex, until the graph is empty.
259 : * The sequence of removed edges will be saved in `OpmphmGraph->removeSequence`.
260 : * The passed OpmphmGraph is will be destroyed.
261 : *
262 : * @param opmphm the OPMPHM
263 : * @param graph the OpmphmGraph
264 : * @param n the number of elements
265 : *
266 : * @retval 0 on Acyclic
267 : * @retval 1 if there is a cycle
268 : */
269 34066 : static int hasCycle (Opmphm * opmphm, OpmphmGraph * graph, size_t n)
270 : {
271 34066 : graph->removeIndex = 0;
272 : // search all vertices
273 28104428 : for (size_t v = 0; v < opmphm->componentSize * opmphm->rUniPar; ++v)
274 : {
275 : // for a vertex with degree 1
276 28070362 : if (graph->vertices[v].degree == 1)
277 : {
278 2635968 : peel_off (opmphm, graph, v);
279 : }
280 : }
281 34066 : if (graph->removeIndex == n)
282 : {
283 : return 0;
284 : }
285 : else
286 : {
287 24318 : return 1;
288 : }
289 : }
290 :
291 : /**
292 : * @brief Provides the minimal `c` value for a given `r`
293 : *
294 : * This minimal values come from Fabiano Cupertino Botelho, Near-Optimal Space Perfect Hashing Algorithms, 2008.
295 : *
296 : * @param r the rUniPar
297 : *
298 : * @retval c the minimal c value
299 : */
300 28 : double opmphmMinC (uint8_t r)
301 : {
302 28 : ELEKTRA_ASSERT (r > 1 && r < 11, "r out of range [2,10]");
303 : switch (r)
304 : {
305 : case 2:
306 : return 2.05;
307 : case 3:
308 : return 1.25;
309 : case 4:
310 : return 1.35;
311 : case 5:
312 : return 1.45;
313 : case 6:
314 : return 1.65;
315 : case 7:
316 : return 1.75;
317 : case 8:
318 : return 1.95;
319 : case 9:
320 : return 2.05;
321 : case 10:
322 : return 2.25;
323 : default:
324 : return 0;
325 : }
326 : }
327 :
328 : /**
329 : * @brief Provides the optimal `r` value for a given `n`
330 : *
331 : * This is a heuristic, the return values follow from the mapping benchmark.
332 : *
333 : * @param n the number of elements to hash
334 : *
335 : * @retval r the optimal rUniPar
336 : */
337 28 : uint8_t opmphmOptR (size_t n)
338 : {
339 28 : ELEKTRA_ASSERT (n > 0, "n is 0");
340 28 : ELEKTRA_ASSERT (n <= KDB_OPMPHM_MAX_N, "n > KDB_OPMPHM_MAX");
341 28 : if (n < 15)
342 : {
343 : return 6;
344 : }
345 4 : else if (n < 30)
346 : {
347 : return 5;
348 : }
349 4 : else if (n < 240)
350 : {
351 : return 4;
352 : }
353 : else
354 : {
355 2 : return 3;
356 : }
357 : }
358 :
359 : /**
360 : * @brief Provides the optimal `c` value for a given `n`
361 : *
362 : * This is a heuristic, the return values follow from the mapping benchmark.
363 : *
364 : * @param n the number of elements to hash
365 : *
366 : * @retval c the optimal `c` value
367 : */
368 28 : double opmphmOptC (size_t n)
369 : {
370 28 : ELEKTRA_ASSERT (n > 0, "n is 0");
371 28 : ELEKTRA_ASSERT (n <= KDB_OPMPHM_MAX_N, "n > KDB_OPMPHM_MAX");
372 28 : if (n < 15)
373 : {
374 : return 1.35;
375 : }
376 4 : else if (n < 30)
377 : {
378 : //~ from 15 to 29 from 2.45 to 1.95
379 0 : return 1 - ((n - 15) * 0.035);
380 : }
381 4 : else if (n < 240)
382 : {
383 : //~ from 30 to 239 from 2.35 to 1.45
384 2 : return 1 - ((n - 30) * 0.0043);
385 : }
386 2 : else if (n < 1280)
387 : {
388 : //~ from 240 to 1279 from 2.25 to 1.35
389 2 : return 1 - ((n - 240) * 0.00086);
390 : }
391 : else
392 : {
393 : return 0.1;
394 : }
395 : }
396 :
397 : /**
398 : * @brief Allocates and initializes the OpmphmGraph.
399 : *
400 : * The OpmphmGraph represents a r-uniform r-partite hypergraph.
401 : * Lazy initializes the `opmphm->hashFunctionSeeds` with r.
402 : * Calculates also the size of one partition in the r-uniform r-partite hypergraph and stores it in `opmphm->componentSize`.
403 : * Allocates all memory for the OpmphmGraph.
404 : *
405 : * @param opmphm the OPMPHM
406 : * @param r the rUniPar
407 : * @param n the number of elements
408 : * @param c space influencing parameter
409 : *
410 : * @retval OpmphmGraph * success
411 : * @retval NULL memory error
412 : */
413 29260 : OpmphmGraph * opmphmGraphNew (Opmphm * opmphm, uint8_t r, size_t n, double c)
414 : {
415 29260 : ELEKTRA_NOT_NULL (opmphm);
416 29260 : ELEKTRA_ASSERT (n > 0, "n is 0");
417 29260 : ELEKTRA_ASSERT (n <= KDB_OPMPHM_MAX_N, "n > KDB_OPMPHM_MAX");
418 29260 : ELEKTRA_ASSERT (c > 0.0, "ratio <= 0");
419 29260 : ELEKTRA_ASSERT (1 < r && r < 11, "r out of range [2,10]");
420 : // lazy create
421 29260 : if (r != opmphm->rUniPar)
422 : {
423 : // free if here
424 29260 : if (opmphm->rUniPar)
425 : {
426 0 : elektraFree (opmphm->hashFunctionSeeds);
427 : }
428 29260 : opmphm->hashFunctionSeeds = elektraMalloc (r * sizeof (int32_t));
429 29260 : if (!opmphm->hashFunctionSeeds)
430 : {
431 : return NULL;
432 : }
433 29260 : opmphm->rUniPar = r;
434 : }
435 : // calculate opmphm->componentSize, number of elements in one part of r-uniform r-partite hypergraph
436 29260 : opmphm->componentSize = (c * n / opmphm->rUniPar) + 1;
437 : // mallocs
438 29260 : OpmphmGraph * graph = elektraMalloc (sizeof (OpmphmGraph));
439 29260 : if (!graph)
440 : {
441 0 : opmphm->componentSize = 0;
442 0 : return NULL;
443 : }
444 29260 : graph->edges = elektraMalloc (n * sizeof (OpmphmEdge));
445 29260 : if (!graph->edges)
446 : {
447 0 : opmphm->componentSize = 0;
448 0 : elektraFree (graph);
449 0 : return NULL;
450 : }
451 29260 : graph->vertices = elektraCalloc (opmphm->componentSize * opmphm->rUniPar * sizeof (OpmphmVertex));
452 29260 : if (!graph->vertices)
453 : {
454 0 : opmphm->componentSize = 0;
455 0 : elektraFree (graph->edges);
456 0 : elektraFree (graph);
457 0 : return NULL;
458 : }
459 : /* one malloc for:
460 : * - graph->removeSequence n
461 : * - graph->edges[i].vertices n * opmphm->rUniPar
462 : * - graph->edges[i].nextEdge n * opmphm->rUniPar
463 : */
464 29260 : uint32_t * removeSequenceVerticesNextEdge = elektraMalloc ((n + 2 * n * opmphm->rUniPar) * sizeof (uint32_t));
465 29260 : if (!removeSequenceVerticesNextEdge)
466 : {
467 0 : opmphm->componentSize = 0;
468 0 : elektraFree (graph->vertices);
469 0 : elektraFree (graph->edges);
470 0 : elektraFree (graph);
471 0 : return NULL;
472 : }
473 : // split removeSequenceVerticesNextEdge for graph->removeSequence, and for graph->edges[].vertices and graph->edges[].nextEdge
474 29260 : graph->removeSequence = &removeSequenceVerticesNextEdge[0];
475 17376764 : for (size_t i = 0; i < n; ++i)
476 : {
477 17347504 : graph->edges[i].vertices = &removeSequenceVerticesNextEdge[n + i * opmphm->rUniPar];
478 17347504 : graph->edges[i].nextEdge = &removeSequenceVerticesNextEdge[(n + opmphm->rUniPar * n) + i * opmphm->rUniPar];
479 : }
480 : return graph;
481 : }
482 :
483 : /**
484 : * @brief Clears the OpmphmGraph.
485 : *
486 : * Sets all vertices to 0.
487 : *
488 : * @param opmphm the OPMPHM
489 : * @param graph the OpmphmGraph
490 : */
491 24318 : void opmphmGraphClear (const Opmphm * opmphm, OpmphmGraph * graph)
492 : {
493 24318 : ELEKTRA_NOT_NULL (opmphm);
494 24318 : ELEKTRA_ASSERT (opmphm->rUniPar > 0 && opmphm->componentSize > 0, "passed opmphm is uninitialized");
495 24318 : ELEKTRA_NOT_NULL (graph);
496 24318 : memset (graph->vertices, 0, opmphm->componentSize * opmphm->rUniPar * sizeof (OpmphmVertex));
497 24318 : }
498 :
499 : /**
500 : * @brief Deletes the OpmphmGraph.
501 : *
502 : * @param graph the OpmphmGraph
503 : */
504 29260 : void opmphmGraphDel (OpmphmGraph * graph)
505 : {
506 29260 : ELEKTRA_NOT_NULL (graph);
507 29260 : elektraFree (graph->removeSequence);
508 29260 : elektraFree (graph->edges);
509 29260 : elektraFree (graph->vertices);
510 29260 : elektraFree (graph);
511 29260 : }
512 :
513 : /**
514 : * @brief Allocates and initializes the OPMPHM.
515 : *
516 : * @retval Opmphm * success
517 : * @retval NULL memory error
518 : */
519 40 : Opmphm * opmphmNew (void)
520 : {
521 29274 : Opmphm * out = elektraMalloc (sizeof (Opmphm));
522 29274 : if (!out)
523 : {
524 : return NULL;
525 : }
526 29274 : out->size = 0;
527 29274 : out->rUniPar = 0;
528 29274 : out->componentSize = 0;
529 40 : return out;
530 : }
531 :
532 : /**
533 : * @brief Copies OPMPHM from source to destination.
534 : *
535 : * Clears the dest and copies memory and values from source.
536 : *
537 : * @param dest the OPMPHM destination
538 : * @param source the OPMPHM source
539 : *
540 : * @retval 0 on success
541 : * @retval -1 on memory error
542 : */
543 12 : int opmphmCopy (Opmphm * dest, const Opmphm * source)
544 : {
545 12 : ELEKTRA_NOT_NULL (dest);
546 12 : ELEKTRA_NOT_NULL (source);
547 : // reset dest
548 12 : opmphmClear (dest);
549 12 : if (dest->rUniPar)
550 : {
551 0 : elektraFree (dest->hashFunctionSeeds);
552 0 : dest->rUniPar = 0;
553 : }
554 12 : dest->componentSize = 0;
555 :
556 : // copy mem
557 12 : if (source->rUniPar)
558 : {
559 12 : dest->hashFunctionSeeds = elektraMalloc (source->rUniPar * sizeof (int32_t));
560 12 : if (!dest->hashFunctionSeeds)
561 : {
562 : return -1;
563 : }
564 12 : memcpy (dest->hashFunctionSeeds, source->hashFunctionSeeds, source->rUniPar * sizeof (int32_t));
565 : }
566 12 : if (source->size)
567 : {
568 12 : dest->graph = elektraMalloc (source->size);
569 12 : if (!dest->graph)
570 : {
571 0 : elektraFree (dest->hashFunctionSeeds);
572 0 : return -1;
573 : }
574 12 : memcpy (dest->graph, source->graph, source->size);
575 : }
576 :
577 : // copy values
578 12 : dest->componentSize = source->componentSize;
579 12 : dest->rUniPar = source->rUniPar;
580 12 : dest->size = source->size;
581 12 : return 0;
582 : }
583 :
584 : /**
585 : * @brief OPMPHM is build.
586 : *
587 : * @param opmphm the OPMPHM
588 : *
589 : * @retval 0 on false
590 : * @retval -1 on true or NULL
591 : */
592 993949 : int opmphmIsBuild (const Opmphm * opmphm)
593 : {
594 1023235 : if (opmphm && opmphm->size)
595 : {
596 : return -1;
597 : }
598 : else
599 : {
600 992883 : return 0;
601 : }
602 : }
603 :
604 : /**
605 : * @brief Deletes the OPMPHM.
606 : *
607 : * Clears and frees all memory in Opmphm.
608 : *
609 : * @param opmphm the OPMPHM
610 : */
611 29274 : void opmphmDel (Opmphm * opmphm)
612 : {
613 29274 : ELEKTRA_NOT_NULL (opmphm);
614 29274 : opmphmClear (opmphm);
615 29274 : if (opmphm->rUniPar)
616 : {
617 29272 : elektraFree (opmphm->hashFunctionSeeds);
618 : }
619 29274 : elektraFree (opmphm);
620 29274 : }
621 :
622 : /**
623 : * @brief Clears the OPMPHM.
624 : *
625 : * The OPMPHM must be successfully created with `opmphmNew ()`.
626 : * Clears and frees all internal memory of Opmphm, but not `Opmphm->hashFunctionSeeds` and the Opmphm instance.
627 : *
628 : * @param opmphm the OPMPHM
629 : */
630 29356 : void opmphmClear (Opmphm * opmphm)
631 : {
632 29356 : ELEKTRA_NOT_NULL (opmphm);
633 29356 : if (opmphmIsBuild (opmphm))
634 : {
635 9760 : elektraFree (opmphm->graph);
636 9760 : opmphm->size = 0;
637 : }
638 29356 : }
639 :
640 : /**
641 : * Hash function
642 : * By Bob Jenkins, May 2006
643 : * http://burtleburtle.net/bob/c/lookup3.c
644 : * Original name: hashlitte
645 : */
646 : #ifndef ELEKTRA_BIG_ENDIAN
647 : // little endian
648 : // sanitize a hash function is silly, so ignore it!
649 : ELEKTRA_NO_SANITIZE_UNDEFINED
650 : ELEKTRA_NO_SANITIZE_INTEGER
651 8994 : uint32_t opmphmHashfunction (const void * key, size_t length, uint32_t initval)
652 : {
653 : uint32_t a, b, c;
654 8994 : a = b = c = 0xdeadbeef + ((uint32_t) length) + initval;
655 8994 : const uint32_t * k = (const uint32_t *) key;
656 19776 : while (length > 12)
657 : {
658 1788 : a += k[0];
659 1788 : b += k[1];
660 1788 : c += k[2];
661 1788 : OPMPHM_HASHFUNCTION_MIX (a, b, c)
662 1788 : length -= 12;
663 1788 : k += 3;
664 : }
665 8994 : switch (length)
666 : {
667 : case 12:
668 42 : c += k[2];
669 42 : b += k[1];
670 42 : a += k[0];
671 42 : break;
672 : case 11:
673 12 : c += k[2] & 0xffffff;
674 12 : b += k[1];
675 12 : a += k[0];
676 12 : break;
677 : case 10:
678 18 : c += k[2] & 0xffff;
679 18 : b += k[1];
680 18 : a += k[0];
681 18 : break;
682 : case 9:
683 6 : c += k[2] & 0xff;
684 6 : b += k[1];
685 6 : a += k[0];
686 6 : break;
687 : case 8:
688 4312 : b += k[1];
689 4312 : a += k[0];
690 4312 : break;
691 : case 7:
692 540 : b += k[1] & 0xffffff;
693 540 : a += k[0];
694 540 : break;
695 : case 6:
696 1548 : b += k[1] & 0xffff;
697 1548 : a += k[0];
698 1548 : break;
699 : case 5:
700 492 : b += k[1] & 0xff;
701 492 : a += k[0];
702 492 : break;
703 : case 4:
704 0 : a += k[0];
705 0 : break;
706 : case 3:
707 80 : a += k[0] & 0xffffff;
708 80 : break;
709 : case 2:
710 1944 : a += k[0] & 0xffff;
711 1944 : break;
712 : case 1:
713 0 : a += k[0] & 0xff;
714 0 : break;
715 : case 0:
716 : return c;
717 : }
718 8994 : OPMPHM_HASHFUNCTION_FINAL (a, b, c);
719 8994 : return c;
720 : }
721 : #else
722 : // big endian
723 : // sanitize a hash function is silly, so ignore it!
724 : ELEKTRA_NO_SANITIZE_UNDEFINED
725 : ELEKTRA_NO_SANITIZE_INTEGER
726 : uint32_t opmphmHashfunction (const void * key, size_t length, uint32_t initval)
727 : {
728 : uint32_t a, b, c;
729 : a = b = c = 0xdeadbeef + ((uint32_t) length) + initval;
730 : const uint8_t * k = (const uint8_t *) key;
731 : while (length > 12)
732 : {
733 : a += k[0];
734 : a += ((uint32_t) k[1]) << 8;
735 : a += ((uint32_t) k[2]) << 16;
736 : a += ((uint32_t) k[3]) << 24;
737 : b += k[4];
738 : b += ((uint32_t) k[5]) << 8;
739 : b += ((uint32_t) k[6]) << 16;
740 : b += ((uint32_t) k[7]) << 24;
741 : c += k[8];
742 : c += ((uint32_t) k[9]) << 8;
743 : c += ((uint32_t) k[10]) << 16;
744 : c += ((uint32_t) k[11]) << 24;
745 : OPMPHM_HASHFUNCTION_MIX (a, b, c);
746 : length -= 12;
747 : k += 12;
748 : }
749 : switch (length)
750 : {
751 : case 12:
752 : c += ((uint32_t) k[11]) << 24;
753 : ELEKTRA_FALLTHROUGH;
754 : case 11:
755 : c += ((uint32_t) k[10]) << 16;
756 : ELEKTRA_FALLTHROUGH;
757 : case 10:
758 : c += ((uint32_t) k[9]) << 8;
759 : ELEKTRA_FALLTHROUGH;
760 : case 9:
761 : c += k[8];
762 : ELEKTRA_FALLTHROUGH;
763 : case 8:
764 : b += ((uint32_t) k[7]) << 24;
765 : ELEKTRA_FALLTHROUGH;
766 : case 7:
767 : b += ((uint32_t) k[6]) << 16;
768 : ELEKTRA_FALLTHROUGH;
769 : case 6:
770 : b += ((uint32_t) k[5]) << 8;
771 : ELEKTRA_FALLTHROUGH;
772 : case 5:
773 : b += k[4];
774 : ELEKTRA_FALLTHROUGH;
775 : case 4:
776 : a += ((uint32_t) k[3]) << 24;
777 : ELEKTRA_FALLTHROUGH;
778 : case 3:
779 : a += ((uint32_t) k[2]) << 16;
780 : ELEKTRA_FALLTHROUGH;
781 : case 2:
782 : a += ((uint32_t) k[1]) << 8;
783 : ELEKTRA_FALLTHROUGH;
784 : case 1:
785 : a += k[0];
786 : break;
787 : case 0:
788 : return c;
789 : }
790 : OPMPHM_HASHFUNCTION_FINAL (a, b, c);
791 : return c;
792 : }
793 : #endif
|