Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #define _GNU_SOURCE
10 : #include <benchmarks.h>
11 : #ifdef HAVE_HSEARCHR
12 : #include <search.h>
13 : #endif
14 : #include <sys/time.h>
15 :
16 : struct timeval start;
17 : int num_dir = NUM_DIR;
18 : int num_key = NUM_KEY;
19 : KeySet * large;
20 :
21 0 : void timeInit (void)
22 : {
23 0 : gettimeofday (&start, 0);
24 0 : }
25 :
26 0 : void timePrint (char * msg)
27 : {
28 : struct timeval measure;
29 : time_t diff;
30 :
31 0 : gettimeofday (&measure, 0);
32 :
33 0 : diff = (measure.tv_sec - start.tv_sec) * 1000000 + (measure.tv_usec - start.tv_usec);
34 0 : fprintf (stdout, "%20s: %20d Microseconds\n", msg, (int) diff);
35 :
36 0 : gettimeofday (&start, 0);
37 0 : }
38 :
39 0 : int timeGetDiffMicroseconds (void)
40 : {
41 : struct timeval measure;
42 : time_t diff;
43 :
44 0 : gettimeofday (&measure, 0);
45 0 : diff = (measure.tv_sec - start.tv_sec) * 1000000 + (measure.tv_usec - start.tv_usec);
46 0 : gettimeofday (&start, 0);
47 :
48 0 : return (int) diff;
49 : }
50 :
51 0 : void benchmarkCreate (void)
52 : {
53 0 : large = ksNew (num_key * num_dir, KS_END);
54 0 : }
55 :
56 0 : void benchmarkFillup (void)
57 : {
58 : int i, j;
59 : char name[KEY_NAME_LENGTH + 1];
60 0 : char value[] = "data";
61 :
62 0 : for (i = 0; i < num_dir; i++)
63 : {
64 0 : snprintf (name, KEY_NAME_LENGTH, "%s/%s%d", KEY_ROOT, "dir", i);
65 0 : ksAppendKey (large, keyNew (name, KEY_VALUE, value, KEY_END));
66 0 : for (j = 0; j < num_key; j++)
67 : {
68 0 : snprintf (name, KEY_NAME_LENGTH, "%s/%s%d/%s%d", KEY_ROOT, "dir", i, "key", j);
69 0 : ksAppendKey (large, keyNew (name, KEY_VALUE, value, KEY_END));
70 : }
71 : }
72 0 : }
73 :
74 :
75 : /**
76 : * Arbitrary Key Set Generator
77 : */
78 :
79 :
80 : /**
81 : * Internal representation of the KsTree
82 : */
83 : typedef struct _KsTreeVertex KsTreeVertex;
84 : struct _KsTreeVertex
85 : {
86 : char * name; /*!< name of the vertex, root has no name */
87 : uint8_t isKey; /*!< when true the path from root to vertex is a Key in the resulting KeySet */
88 : uint8_t isLink; /*!< determines if vertex is link, used at recFreeKsTree (...) */
89 : struct _KsTreeVertex ** children; /*!< stores the children */
90 : #ifdef HAVE_HSEARCHR
91 : struct hsearch_data * htab; /*!< stores the Hash Map, containing the children names */
92 : #endif
93 : size_t numberofChildren; /*!< number of the stored children */
94 : size_t mallocSize; /*!< size malloced for the children */
95 : };
96 :
97 : /**
98 : * Declares the label storage and some config
99 : */
100 : const uint8_t maxNameGenerationTries = 99;
101 : #define NUMBER_OF_LABELS 10
102 : static KsTreeVertex * labels[NUMBER_OF_LABELS];
103 :
104 : static void * shapeDefaultInit (void);
105 : static void shapeDefaultDel (void * data);
106 : static void shapefDefault (const size_t initSize, size_t size, size_t level, int32_t * seed, KsShapeFunctionReturn * ret, void * data);
107 :
108 : const char * const alphabetnumbers = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
109 : const char * const alphabetspecial = "^!\"$`%&/{([)]=} %?\\+*~#';,:§.-_|<>¸¬½¼³²¹ł€¶øæßð𳽫»¢“”nµ─·";
110 :
111 :
112 : #ifdef HAVE_HSEARCHR
113 : /**
114 : * @brief Creates the Hash Map for a given vertex.
115 : *
116 : * vertex->mallocSize must be set.
117 : *
118 : * @param vertex the vertex
119 : */
120 0 : static void createHashMap (KsTreeVertex * vertex)
121 : {
122 0 : vertex->htab = elektraCalloc (sizeof (struct hsearch_data));
123 0 : if (!vertex->htab || !hcreate_r (vertex->mallocSize, vertex->htab))
124 : {
125 0 : printExit ("recGenerateKsTree: can not create Hash Map");
126 : }
127 0 : }
128 :
129 : /**
130 : * @brief Deletes the Hash Map for a given vertex.
131 : *
132 : * @param vertex the vertex
133 : */
134 : static void deleteHashMap (KsTreeVertex * vertex)
135 : {
136 0 : hdestroy_r (vertex->htab);
137 0 : elektraFree (vertex->htab);
138 : }
139 : /**
140 : * @brief Searches in the Hash Map of vertex for the name.
141 : *
142 : * If not in vertex insert it.
143 : *
144 : * @param vertex the vertex
145 : * @param name the name to search
146 : *
147 : * @retval 1 if not in vertex, unique
148 : * @retval 0 if in vertex, not unique
149 : */
150 0 : static int searchHashMap (KsTreeVertex * vertex, char * name)
151 : {
152 : ENTRY e;
153 : ENTRY * ep;
154 0 : e.key = name;
155 0 : e.data = NULL;
156 0 : if (!hsearch_r (e, FIND, &ep, vertex->htab))
157 : {
158 : // not in Hash Map, insert
159 0 : if (!hsearch_r (e, ENTER, &ep, vertex->htab))
160 : {
161 0 : printExit ("recGenerateKsTree: can not insert in Hash Map");
162 : }
163 : return 1;
164 : }
165 : else
166 : {
167 : return 0;
168 : }
169 : }
170 : #else
171 : // no hsearch use dummys and linear search
172 : static void createHashMap (KsTreeVertex * vertex ELEKTRA_UNUSED)
173 : {
174 : }
175 : static void deleteHashMap (KsTreeVertex * vertex ELEKTRA_UNUSED)
176 : {
177 : }
178 : static int searchHashMap (KsTreeVertex * vertex, char * name)
179 : {
180 : for (size_t i = 0; i < vertex->numberofChildren; ++i)
181 : {
182 : if (!strcmp (vertex->children[i]->name, name))
183 : {
184 : return 0;
185 : }
186 : }
187 : return 1;
188 : }
189 : #endif
190 :
191 : /**
192 : * @brief Fills a string up with random chars and null terminates it.
193 : *
194 : * @param name the string
195 : * @param length the length of the string (excluding the '\0')
196 : * @param seed to generate random data
197 : * @param shape the shape of the KeySet
198 : */
199 0 : static void fillUpWithRandomChars (char * name, size_t length, int32_t * seed, KeySetShape * shape)
200 : {
201 : // throw the dice and use 8 bit of each byte from seed for one char, determination if special or not and which
202 0 : elektraRand (seed);
203 0 : size_t i = 0;
204 0 : size_t s = i;
205 0 : char * c = name;
206 0 : bool done = false;
207 0 : while (!done)
208 : {
209 0 : uint8_t ds = (*seed >> (8 * s * 2)) & 0xFF;
210 0 : uint8_t dc = (*seed >> (8 * (s * 2 + 1))) & 0xFF;
211 : // special or not
212 0 : bool special = shape->special && (ds % shape->special) == 0;
213 : // choose
214 0 : if (special)
215 : {
216 0 : *c = alphabetspecial[dc % strlen (alphabetspecial)];
217 : }
218 : else
219 : {
220 0 : *c = alphabetnumbers[dc % strlen (alphabetnumbers)];
221 : }
222 0 : ++c;
223 0 : ++i;
224 0 : ++s;
225 0 : if (i == length)
226 : {
227 : done = true;
228 : }
229 0 : else if (s == 2)
230 : {
231 0 : elektraRand (seed);
232 0 : s = 0;
233 : }
234 : }
235 0 : *c = '\0';
236 0 : }
237 :
238 : /**
239 : * @brief Recursively calculate the number of vertices with isKey set to 1 starting from vertex.
240 : *
241 : * @param vertex the staring
242 : */
243 0 : static size_t getSizeOfVertex (KsTreeVertex * vertex)
244 : {
245 0 : size_t size = 0;
246 0 : if (vertex->isKey)
247 : {
248 0 : ++size;
249 : }
250 0 : for (size_t i = 0; i < vertex->numberofChildren; ++i)
251 : {
252 0 : size += getSizeOfVertex (vertex->children[i]);
253 : }
254 0 : return size;
255 : }
256 :
257 : /**
258 : * @brief Generate a name for a vertex.
259 : *
260 : * Generates a name and looks in the parent if the name is unique, if not try until maxNameGenerationTries * (maxLength - length + 1)
261 : * is exceeded. The length is extended every maxNameGenerationTries by one until maxWordLength is reached.
262 : *
263 : * @param parent the parent vertex
264 : * @param seed the seed for random actions, already randomized
265 : * @param shape the KeySetShape
266 : *
267 : * @retval char * the generated name
268 : */
269 0 : static char * generateName (KsTreeVertex * parent, int32_t * seed, KeySetShape * shape)
270 : {
271 0 : char * out = elektraMalloc ((shape->maxWordLength + 1) * sizeof (char));
272 0 : if (!out)
273 : {
274 0 : printExit ("recGenerateKsTree: malloc vertex->name");
275 : }
276 0 : int32_t dl = *seed & 0xFFFFFF;
277 0 : size_t length = (dl % (shape->maxWordLength - shape->minWordLength + 1)) + shape->minWordLength;
278 : uint8_t uniqueName;
279 0 : uint8_t nameGenerationTries = 0;
280 : do
281 : {
282 : // generate name and see if name is unique
283 0 : fillUpWithRandomChars (out, length, seed, shape);
284 0 : uniqueName = searchHashMap (parent, out);
285 0 : ++nameGenerationTries;
286 0 : if (nameGenerationTries > maxNameGenerationTries && !uniqueName)
287 : {
288 : // make word longer if possible
289 0 : if (length < shape->maxWordLength)
290 : {
291 :
292 0 : ++length;
293 : // start new
294 0 : nameGenerationTries = 0;
295 : }
296 : else
297 : {
298 0 : printExit ("recGenerateKsTree: max name generation tries exceeded");
299 : }
300 : }
301 0 : } while (!uniqueName);
302 0 : return out;
303 : }
304 :
305 : /**
306 : * @brief Recursively generates a KsTree.
307 : *
308 : * Every invocation generates a vertex. First the name and after the KeySetShape->shapef invocation the children by recursion.
309 : *
310 : * @param parent the parent vertex
311 : * @param size the target number of vertices where isKey is 1
312 : * @param actualSize the number of vertices where isKey is 1 so far
313 : * @param level the actual level
314 : * @param seed the seed for random actions
315 : * @param shape the KeySetShape
316 : * @param data the data passed to the KeySetShape->shapef function
317 : *
318 : * @retval KsTreeVertex * the generated vertex
319 : */
320 0 : static KsTreeVertex * recGenerateKsTree (KsTreeVertex * parent, const size_t size, size_t * actualSize, size_t level, int32_t * seed,
321 : KeySetShape * shape, void * data)
322 : {
323 : // create actual vertex
324 0 : KsTreeVertex * vertex = elektraMalloc (sizeof (KsTreeVertex));
325 0 : if (!vertex)
326 : {
327 0 : printExit ("recGenerateKsTree: malloc vertex");
328 : }
329 : // default not a key
330 0 : vertex->isKey = 0;
331 0 : elektraRand (seed);
332 : // used for parent determination
333 0 : int8_t dp = *seed >> 24;
334 : // vertex name generation
335 0 : vertex->name = generateName (parent, seed, shape);
336 : // determine subKeys and label
337 : KsShapeFunctionReturn ret;
338 0 : shape->shapef (size, *actualSize, level, seed, &ret, data);
339 : // if too many set max
340 0 : if (ret.subKeys > (ssize_t) *actualSize + 1)
341 : {
342 0 : ret.subKeys = *actualSize;
343 : }
344 0 : if (ret.subKeys >= 0)
345 : {
346 0 : vertex->isLink = 0;
347 : // vertex children generation
348 0 : if (ret.subKeys > 0)
349 : {
350 : // create branch
351 : // remove costs for subkeys
352 0 : *actualSize -= (ret.subKeys - 1); // the cost for one is included in the size from the parent call
353 : // see if parent
354 0 : if (*actualSize && shape->parent && (dp % shape->parent) == 0)
355 : {
356 : // counts extra so costs need to be removed
357 0 : --*actualSize;
358 0 : vertex->isKey = 1;
359 : }
360 : // prepare children
361 0 : vertex->numberofChildren = 0;
362 0 : vertex->mallocSize = ret.subKeys;
363 0 : createHashMap (vertex);
364 0 : vertex->children = elektraMalloc (vertex->mallocSize * sizeof (KsTreeVertex *));
365 0 : if (!vertex->children)
366 : {
367 0 : printExit ("recGenerateKsTree: malloc children");
368 : }
369 0 : ++level;
370 : // make children
371 0 : for (size_t i = 0; i < vertex->mallocSize; ++i)
372 : {
373 0 : vertex->children[i] = recGenerateKsTree (vertex, size, actualSize, level, seed, shape, data);
374 0 : ++vertex->numberofChildren;
375 : }
376 : }
377 : else
378 : {
379 : // terminate branch
380 0 : vertex->isKey = 1;
381 0 : vertex->numberofChildren = 0;
382 : }
383 0 : if (ret.label)
384 : {
385 : // set label at vertex
386 0 : if (ret.label > NUMBER_OF_LABELS)
387 : {
388 0 : printExit ("recGenerateKsTree: label > NUMBER_OF_LABELS");
389 : }
390 0 : --ret.label;
391 0 : labels[ret.label] = vertex;
392 : }
393 : }
394 : else
395 : {
396 : // links will not be followed by recFreeKsTree (...)
397 0 : vertex->isLink = 1;
398 0 : if (!ret.label || ret.label > NUMBER_OF_LABELS)
399 : {
400 0 : printExit ("recGenerateKsTree: subKeys < 0 but no label set or label > NUMBER_OF_LABELS");
401 : }
402 : // take children from label vertex
403 0 : --ret.label;
404 0 : KsTreeVertex * linkVertex = labels[ret.label];
405 : // copy children, if space actualSize includes the costs for the actual key
406 0 : size_t linkTreeSize = getSizeOfVertex (linkVertex) - 1;
407 : // linkVertex->isKey will not be copied, so remove it from size if set
408 0 : if (linkVertex->isKey)
409 : {
410 0 : --linkTreeSize;
411 : }
412 0 : if (*actualSize >= linkTreeSize)
413 : {
414 0 : vertex->mallocSize = linkVertex->mallocSize;
415 0 : vertex->numberofChildren = linkVertex->numberofChildren;
416 0 : vertex->children = linkVertex->children;
417 0 : *actualSize -= linkTreeSize;
418 : // link has children so it can have a parent
419 0 : if (*actualSize && shape->parent && (dp % shape->parent) == 0)
420 : {
421 : // counts extra so costs need to be removed
422 0 : --*actualSize;
423 0 : vertex->isKey = 1;
424 : }
425 : }
426 : else
427 : {
428 : // if no space terminate branch
429 0 : vertex->numberofChildren = 0;
430 0 : vertex->isKey = 1;
431 : }
432 : }
433 0 : return vertex;
434 : }
435 :
436 : /**
437 : * @brief Transforms a given branch of the KsTree to a KeySet.
438 : *
439 : * The KeySet and Key must be initialized. Every vertex with isKey set will be a Key in the resulting KeySet.
440 : * The resulting Key name is every KsTreeVertex->name in the path from root to vertex.
441 : *
442 : * @param ks the KeySet
443 : * @param key the actual Key
444 : * @param vertex starting point
445 : *
446 : * @retval KeySet * the resulting KeySet
447 : */
448 0 : static void recGenerateKeySet (KeySet * ks, Key * key, KsTreeVertex * vertex)
449 : {
450 : // add name to key
451 0 : if (keyAddBaseName (key, vertex->name) < 0)
452 : {
453 0 : printExit ("recGenerateKeySet: Can not add KeyBaseName ");
454 : }
455 : // add if Key
456 0 : if (vertex->isKey)
457 : {
458 0 : Key * dupKey = keyDup (key);
459 0 : if (!dupKey)
460 : {
461 0 : printExit ("recGenerateKeySet: Can not dup Key");
462 : }
463 0 : ssize_t sizeBefore = ksGetSize (ks);
464 0 : if (ksAppendKey (ks, dupKey) < 0)
465 : {
466 0 : printExit ("recGenerateKeySet: Can not add Key");
467 : }
468 0 : if (sizeBefore == ksGetSize (ks))
469 : {
470 0 : printExit ("recGenerateKeySet: Add Key with on effect");
471 : }
472 : }
473 : // go to children
474 0 : for (size_t i = 0; i < vertex->numberofChildren; ++i)
475 : {
476 0 : Key * dupKey = keyDup (key);
477 0 : if (!dupKey)
478 : {
479 0 : printExit ("recGenerateKeySet: Can not dup Key");
480 : }
481 0 : recGenerateKeySet (ks, dupKey, vertex->children[i]);
482 : }
483 0 : keyDel (key);
484 0 : }
485 :
486 : /**
487 : * @brief Frees recursively to whole KsTree under the passed vertex.
488 : *
489 : * @param vertex the start vertex
490 : */
491 0 : static void recFreeKsTree (KsTreeVertex * vertex)
492 : {
493 0 : if (!vertex->isLink)
494 : {
495 0 : for (size_t i = 0; i < vertex->numberofChildren; ++i)
496 : {
497 0 : recFreeKsTree (vertex->children[i]);
498 : }
499 : }
500 0 : if (vertex->name) elektraFree (vertex->name);
501 0 : if (vertex->numberofChildren && !vertex->isLink)
502 : {
503 0 : elektraFree (vertex->children);
504 0 : deleteHashMap (vertex);
505 : }
506 0 : elektraFree (vertex);
507 0 : }
508 :
509 : /**
510 : * @brief Generates a KeySet.
511 : *
512 : * Generates a KsTree and transforms the KsTree to the resulting KeySet.
513 : *
514 : * @param size the desired KeySet size
515 : * @param seed the seed for the random generation
516 : * @param shape the KeySetShape
517 : *
518 : * @retval KeySet * the resulting KeySet
519 : */
520 0 : KeySet * generateKeySet (const size_t size, int32_t * seed, KeySetShape * shape)
521 : {
522 0 : ELEKTRA_ASSERT (size > 4, "size < 5");
523 0 : int32_t defaultSeed = 1;
524 0 : if (!seed)
525 : {
526 0 : seed = &defaultSeed;
527 : }
528 : KeySetShape shapeDefault;
529 0 : if (!shape)
530 : {
531 : /**
532 : * Default KeySetShape
533 : */
534 0 : shapeDefault.parent = 3;
535 0 : shapeDefault.special = 50;
536 0 : shapeDefault.minWordLength = 4;
537 0 : shapeDefault.maxWordLength = 7;
538 0 : shapeDefault.shapeInit = shapeDefaultInit;
539 0 : shapeDefault.shapef = shapefDefault;
540 0 : shapeDefault.shapeDel = shapeDefaultDel;
541 :
542 0 : shape = &shapeDefault;
543 : }
544 0 : ELEKTRA_ASSERT (shape->minWordLength <= shape->maxWordLength, "minWordLength > maxWordLength");
545 0 : ELEKTRA_ASSERT (shape->maxWordLength - shape->minWordLength <= 16777215, "max world length variation exceeded 16777215");
546 0 : ELEKTRA_ASSERT (shape->parent <= 127, "parent > 127");
547 0 : ELEKTRA_ASSERT (shape->special <= 127, "parent > 127");
548 0 : ELEKTRA_ASSERT (shape->minWordLength != 0, "minWordLength is 0");
549 0 : ELEKTRA_ASSERT (shape->maxWordLength != 0, "maxWordLength is 0");
550 0 : ELEKTRA_ASSERT (shape->shapef, "shape->shapef");
551 0 : ELEKTRA_ASSERT ((shape->shapeInit && shape->shapeDel) || (!shape->shapeInit && !shape->shapeDel),
552 : "shape->shapeInit or shape->shapeDel not set");
553 : // init data
554 0 : void * data = NULL;
555 0 : if (shape->shapeInit)
556 : {
557 0 : data = shape->shapeInit ();
558 0 : if (!data)
559 : {
560 0 : printExit ("generateKeySet: shapeInit returned NULL");
561 : }
562 : }
563 : // create root and init root
564 0 : KsTreeVertex * root = elektraMalloc (sizeof (KsTreeVertex));
565 0 : if (!root)
566 : {
567 0 : printExit ("generateKeySet: malloc root vertex");
568 : }
569 0 : root->name = NULL;
570 0 : root->isKey = 0;
571 0 : root->isLink = 0;
572 0 : root->mallocSize = size;
573 0 : createHashMap (root);
574 0 : root->numberofChildren = 0;
575 0 : root->children = elektraMalloc (root->mallocSize * sizeof (KsTreeVertex *));
576 0 : if (!root->children)
577 : {
578 0 : printExit ("generateKeySet: root children malloc");
579 : }
580 : // generate ksTree
581 0 : size_t actualSize = size;
582 0 : while (actualSize)
583 : {
584 0 : --actualSize;
585 0 : root->children[root->numberofChildren] = recGenerateKsTree (root, size, &actualSize, 1, seed, shape, data);
586 0 : ++root->numberofChildren;
587 : }
588 : // del data
589 0 : if (shape->shapeDel)
590 : {
591 0 : shape->shapeDel (data);
592 : }
593 : // generate KeySet out of KsTree
594 0 : KeySet * ks = ksNew (size, KS_END);
595 0 : if (!ks)
596 : {
597 0 : printExit ("generateKeySet: Can not create KeySet");
598 : }
599 0 : for (size_t i = 0; i < root->numberofChildren; ++i)
600 : {
601 0 : Key * key = keyNew ("", KEY_END);
602 0 : if (!key)
603 : {
604 0 : printExit ("generateKeySet: Can not create Key");
605 : }
606 0 : recGenerateKeySet (ks, key, root->children[i]);
607 : }
608 : // delete KsTree
609 0 : recFreeKsTree (root);
610 0 : return ks;
611 : }
612 :
613 : /**
614 : * Default KeySetShape
615 : *
616 : * Create two labels at second level and use them constantly.
617 : * The KeySet with default seed and 20 elements looks like:
618 : *
619 : * /6iyrg67
620 : * /6iyrg67/CFQK5/t24RHQJ/mvh*Hr
621 : * /6iyrg67/CFQK5/wxaP1Ar
622 : * /6iyrg67/CFQK5/wxaP1Ar/7'FE
623 : * /6iyrg67/jdEm/EYFex
624 : * /6iyrg67/jdEm/EYFex/nGH5z
625 : * /6iyrg67/jdEm/c5oY8cj/nd3C5L
626 : * /KZUr/TWNK/EYFex
627 : * /KZUr/TWNK/EYFex/nGH5z
628 : * /KZUr/TWNK/c5oY8cj/nd3C5L
629 : * /KZUr/csj9t/t24RHQJ/mvh*Hr
630 : * /KZUr/csj9t/wxaP1Ar
631 : * /KZUr/csj9t/wxaP1Ar/7'FE
632 : * /u002/sACrr
633 : * /u002/sACrr/EYFex
634 : * /u002/sACrr/EYFex/nGH5z
635 : * /u002/sACrr/c5oY8cj/nd3C5L
636 : * /u002/y10bqcj/t24RHQJ/mvh*Hr
637 : * /u002/y10bqcj/wxaP1Ar
638 : * /u002/y10bqcj/wxaP1Ar/7'FE
639 : */
640 0 : static void * shapeDefaultInit (void)
641 : {
642 0 : void * data = elektraMalloc (3 * sizeof (uint8_t));
643 0 : if (!data)
644 : {
645 : return NULL;
646 : }
647 0 : uint8_t * b = data;
648 : // three boolean flags
649 0 : b[0] = 0; // if first label was set
650 0 : b[1] = 0; // if second label was set
651 0 : b[2] = 0; // alternation bit, to use the labels
652 0 : return data;
653 : }
654 0 : static void shapeDefaultDel (void * data)
655 : {
656 0 : elektraFree (data);
657 0 : }
658 0 : static void shapefDefault (const size_t initSize ELEKTRA_UNUSED, size_t size ELEKTRA_UNUSED, size_t level, int32_t * seed ELEKTRA_UNUSED,
659 : KsShapeFunctionReturn * ret, void * data)
660 : {
661 0 : uint8_t * labelSet = data;
662 0 : if (level == 1)
663 : {
664 : // create 2 keys
665 0 : ret->subKeys = 2;
666 0 : ret->label = 0;
667 : }
668 0 : else if (level == 2)
669 : {
670 0 : if (!labelSet[0] && !labelSet[1])
671 : {
672 : // no label set, so set the first one
673 0 : ret->subKeys = 2;
674 0 : ret->label = 1;
675 0 : labelSet[0] = 1;
676 : }
677 0 : else if (labelSet[0] && !labelSet[1])
678 : {
679 : // first one set, so set the second
680 0 : ret->subKeys = 2;
681 0 : ret->label = 2;
682 0 : labelSet[1] = 1;
683 : }
684 : else
685 : {
686 : // both set, alternation to assign
687 0 : ret->subKeys = -1;
688 0 : if (labelSet[2])
689 : {
690 0 : ret->label = 1;
691 0 : labelSet[2] = 0;
692 : }
693 : else
694 : {
695 0 : ret->label = 2;
696 0 : labelSet[2] = 1;
697 : }
698 : }
699 : }
700 0 : else if (level == 3)
701 : {
702 : // some names after labels
703 0 : ret->subKeys = 1;
704 0 : ret->label = 0;
705 : }
706 : else
707 : {
708 : // terminate branch
709 0 : ret->subKeys = 0;
710 0 : ret->label = 0;
711 : }
712 0 : }
713 :
714 : /**
715 : * @brief Print message to stderr and exit with failure code.
716 : *
717 : * @param msg the message
718 : */
719 0 : void printExit (const char * msg)
720 : {
721 0 : fprintf (stderr, "FATAL: %s\n", msg);
722 0 : exit (EXIT_FAILURE);
723 : }
|