LCOV - code coverage report
Current view: top level - src/libs/elektra - opmphm.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 234 258 90.7 %
Date: 2019-09-12 12:28:41 Functions: 17 28 60.7 %

          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

Generated by: LCOV version 1.13