Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for DynArray, a simple dynamic array for meta-key deduplication.
5 : *
6 : * The DynArray is used to store pointers of meta-keys. The dynArrayFindOrInsert function
7 : * searches for a pointer in the structure. If it is not yet in the array, it will be inserted.
8 : * If the underlying array is too small, it is resized such that it can accomodate further elements.
9 : * The dynArrayFind function only searches for elements.
10 : *
11 : * The mmapstorage plugin uses the DynArray to deduplicate meta-keys.
12 : *
13 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
14 : *
15 : */
16 :
17 : #include "dynarray.h"
18 :
19 : #include <kdblogger.h>
20 :
21 : /* -- DynArray Implementation ----------------------------------------------------------------------------------------------------------- */
22 :
23 : #define ELEKTRA_MMAP_DYNARRAY_MINSIZE (8)
24 :
25 : /**
26 : * @brief Allocator for DynArray.
27 : *
28 : * @return newly allocated DynArray
29 : */
30 346 : DynArray * ELEKTRA_PLUGIN_FUNCTION (dynArrayNew) (void)
31 : {
32 346 : DynArray * dynArray = elektraCalloc (sizeof (DynArray));
33 346 : dynArray->keyArray = elektraCalloc (sizeof (Key *) * ELEKTRA_MMAP_DYNARRAY_MINSIZE);
34 346 : dynArray->mappedKeyArray = 0;
35 346 : dynArray->size = 0;
36 346 : dynArray->alloc = ELEKTRA_MMAP_DYNARRAY_MINSIZE;
37 346 : return dynArray;
38 : }
39 :
40 : /**
41 : * @brief Deallocator for DynArray.
42 : *
43 : * @param dynArray to be free()'d
44 : */
45 348 : void ELEKTRA_PLUGIN_FUNCTION (dynArrayDelete) (DynArray * dynArray)
46 : {
47 348 : if (!dynArray)
48 : {
49 : return;
50 : }
51 346 : if (dynArray->keyArray)
52 : {
53 346 : elektraFree (dynArray->keyArray);
54 : }
55 346 : if (dynArray->mappedKeyArray)
56 : {
57 97 : elektraFree (dynArray->mappedKeyArray);
58 : }
59 346 : elektraFree (dynArray);
60 : }
61 :
62 : /**
63 : * @brief Find position or insert Key pointer into DynArray.
64 : *
65 : * @param key to be found or inserted
66 : * @param dynArray where the key should be searched for or inserted
67 : *
68 : * @retval -1 on memory error (malloc failed), or size exceeded
69 : * @retval 0 if the key was inserted
70 : * @retval 1 if the key was found
71 : */
72 505 : int ELEKTRA_PLUGIN_FUNCTION (dynArrayFindOrInsert) (Key * key, DynArray * dynArray)
73 : {
74 505 : size_t l = 0;
75 505 : size_t h = dynArray->size;
76 : ELEKTRA_LOG_DEBUG ("l: %zu", l);
77 : ELEKTRA_LOG_DEBUG ("h: %zu", h);
78 : ELEKTRA_LOG_DEBUG ("dynArray->size: %zu", dynArray->size);
79 : ELEKTRA_LOG_DEBUG ("dynArray->alloc: %zu", dynArray->alloc);
80 :
81 2392 : while (l < h)
82 : {
83 1386 : size_t m = (l + h) >> 1;
84 : ELEKTRA_LOG_DEBUG ("m: %zu", m);
85 :
86 1386 : if (dynArray->keyArray[m] > key)
87 : {
88 : h = m;
89 : }
90 554 : else if (dynArray->keyArray[m] < key)
91 : {
92 550 : l = ++m;
93 : }
94 : else
95 : {
96 : return 1; // found
97 : }
98 : }
99 : // insert key at index l
100 501 : if (dynArray->size == dynArray->alloc)
101 : {
102 : // doubling the array size to keep reallocations logarithmic
103 8 : size_t oldAllocSize = dynArray->alloc;
104 8 : if (oldAllocSize > (SIZE_MAX / 2))
105 : {
106 : return -1; // error
107 : }
108 8 : Key ** new = elektraCalloc ((2 * oldAllocSize) * sizeof (Key *));
109 8 : memcpy (new, dynArray->keyArray, dynArray->size * sizeof (Key *));
110 8 : elektraFree (dynArray->keyArray);
111 8 : dynArray->keyArray = new;
112 8 : dynArray->alloc = 2 * oldAllocSize;
113 : }
114 :
115 501 : memmove ((void *) (dynArray->keyArray + l + 1), (void *) (dynArray->keyArray + l), ((dynArray->size) - l) * (sizeof (size_t)));
116 501 : dynArray->keyArray[l] = key;
117 501 : dynArray->size += 1;
118 :
119 501 : return 0; // inserted
120 : }
121 :
122 : /**
123 : * @brief Find Key pointer in the DynArray.
124 : *
125 : * @param key Key pointer to search for
126 : * @param dynArray where the Key should be searched for
127 : *
128 : * @return position of the Key pointer in the DynArray, or -1 if not found or size exceeded
129 : */
130 305 : ssize_t ELEKTRA_PLUGIN_FUNCTION (dynArrayFind) (Key * key, DynArray * dynArray)
131 : {
132 305 : size_t l = 0;
133 305 : size_t h = dynArray->size;
134 : ELEKTRA_LOG_DEBUG ("l: %zu", l);
135 : ELEKTRA_LOG_DEBUG ("h: %zu", h);
136 : ELEKTRA_LOG_DEBUG ("dynArray->size: %zu", dynArray->size);
137 : ELEKTRA_LOG_DEBUG ("dynArray->alloc: %zu", dynArray->alloc);
138 :
139 850 : while (l < h)
140 : {
141 545 : size_t m = (l + h) >> 1;
142 : ELEKTRA_LOG_DEBUG ("m: %zu", m);
143 :
144 545 : if (dynArray->keyArray[m] > key)
145 : {
146 : h = m;
147 : }
148 399 : else if (dynArray->keyArray[m] < key)
149 : {
150 94 : l = ++m;
151 : }
152 : else
153 : {
154 305 : if (m < SSIZE_MAX)
155 : {
156 305 : return m; // found
157 : }
158 : else
159 : {
160 : return -1;
161 : }
162 : }
163 : }
164 :
165 : return -1;
166 : }
|