1 /***********************************************************************************************************************************
2 Key Value Handler
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5
6 #include <limits.h>
7
8 #include "common/debug.h"
9 #include "common/memContext.h"
10 #include "common/type/keyValue.h"
11 #include "common/type/list.h"
12 #include "common/type/variantList.h"
13
14 /***********************************************************************************************************************************
15 Contains information about the key value store
16 ***********************************************************************************************************************************/
17 struct KeyValue
18 {
19 KeyValuePub pub; // Publicly accessible variables
20 List *list; // List of keys/values
21 };
22
23 /***********************************************************************************************************************************
24 Contains information about an individual key/value pair
25 ***********************************************************************************************************************************/
26 typedef struct KeyValuePair
27 {
28 Variant *key; // The key
29 Variant *value; // The value (this may be NULL)
30 } KeyValuePair;
31
32 /**********************************************************************************************************************************/
33 KeyValue *
kvNew(void)34 kvNew(void)
35 {
36 FUNCTION_TEST_VOID();
37
38 KeyValue *this = NULL;
39
40 MEM_CONTEXT_NEW_BEGIN("KeyValue")
41 {
42 // Allocate state and set context
43 this = memNew(sizeof(KeyValue));
44
45 *this = (KeyValue)
46 {
47 .pub =
48 {
49 .memContext = MEM_CONTEXT_NEW(),
50 .keyList = varLstNew(),
51 },
52 .list = lstNewP(sizeof(KeyValuePair)),
53 };
54 }
55 MEM_CONTEXT_NEW_END();
56
57 FUNCTION_TEST_RETURN(this);
58 }
59
60 /**********************************************************************************************************************************/
61 KeyValue *
kvDup(const KeyValue * source)62 kvDup(const KeyValue *source)
63 {
64 FUNCTION_TEST_BEGIN();
65 FUNCTION_TEST_PARAM(KEY_VALUE, source);
66 FUNCTION_TEST_END();
67
68 ASSERT(source != NULL);
69
70 KeyValue *this = kvNew();
71
72 // Duplicate all key/values
73 for (unsigned int listIdx = 0; listIdx < lstSize(source->list); listIdx++)
74 {
75 const KeyValuePair *sourcePair = (const KeyValuePair *)lstGet(source->list, listIdx);
76
77 // Copy the pair
78 KeyValuePair pair;
79 pair.key = varDup(sourcePair->key);
80 pair.value = varDup(sourcePair->value);
81
82 // Add to the list
83 lstAdd(this->list, &pair);
84 }
85
86 this->pub.keyList = varLstDup(kvKeyList(source));
87
88 FUNCTION_TEST_RETURN(this);
89 }
90
91 /**********************************************************************************************************************************/
92 unsigned int
kvGetIdx(const KeyValue * this,const Variant * key)93 kvGetIdx(const KeyValue *this, const Variant *key)
94 {
95 FUNCTION_TEST_BEGIN();
96 FUNCTION_TEST_PARAM(KEY_VALUE, this);
97 FUNCTION_TEST_PARAM(VARIANT, key);
98 FUNCTION_TEST_END();
99
100 ASSERT(this != NULL);
101 ASSERT(key != NULL);
102
103 // Search for the key
104 unsigned int result = KEY_NOT_FOUND;
105
106 for (unsigned int listIdx = 0; listIdx < lstSize(this->list); listIdx++)
107 {
108 const KeyValuePair *pair = (const KeyValuePair *)lstGet(this->list, listIdx);
109
110 // Break if the key matches
111 if (varEq(key, pair->key))
112 {
113 result = listIdx;
114 break;
115 }
116 }
117
118 FUNCTION_TEST_RETURN(result);
119 }
120
121 /***********************************************************************************************************************************
122 Internal put key/value pair
123
124 Handles the common logic for the external put functions. The correct mem context should be set before calling this function.
125 ***********************************************************************************************************************************/
126 static void
kvPutInternal(KeyValue * this,const Variant * key,Variant * value)127 kvPutInternal(KeyValue *this, const Variant *key, Variant *value)
128 {
129 FUNCTION_TEST_BEGIN();
130 FUNCTION_TEST_PARAM(KEY_VALUE, this);
131 FUNCTION_TEST_PARAM(VARIANT, key);
132 FUNCTION_TEST_PARAM(VARIANT, value);
133 FUNCTION_TEST_END();
134
135 ASSERT(this != NULL);
136 ASSERT(key != NULL);
137
138 // Find the key
139 unsigned int listIdx = kvGetIdx(this, key);
140
141 // If the key was not found then add it
142 if (listIdx == KEY_NOT_FOUND)
143 {
144 // Copy the pair
145 KeyValuePair pair;
146 pair.key = varDup(key);
147 pair.value = value;
148
149 // Add to the list
150 lstAdd(this->list, &pair);
151
152 // Add to the key list
153 varLstAdd(this->pub.keyList, varDup(key));
154 }
155 // Else update it
156 else
157 {
158 KeyValuePair *pair = (KeyValuePair *)lstGet(this->list, listIdx);
159
160 if (pair->value != NULL)
161 varFree(pair->value);
162
163 pair->value = value;
164 }
165
166 FUNCTION_TEST_RETURN_VOID();
167 }
168
169 /**********************************************************************************************************************************/
170 KeyValue *
kvPut(KeyValue * this,const Variant * key,const Variant * value)171 kvPut(KeyValue *this, const Variant *key, const Variant *value)
172 {
173 FUNCTION_TEST_BEGIN();
174 FUNCTION_TEST_PARAM(KEY_VALUE, this);
175 FUNCTION_TEST_PARAM(VARIANT, key);
176 FUNCTION_TEST_PARAM(VARIANT, value);
177 FUNCTION_TEST_END();
178
179 ASSERT(this != NULL);
180 ASSERT(key != NULL);
181
182 MEM_CONTEXT_BEGIN(this->pub.memContext)
183 {
184 kvPutInternal(this, key, varDup(value));
185 }
186 MEM_CONTEXT_END();
187
188 FUNCTION_TEST_RETURN(this);
189 }
190
191 /**********************************************************************************************************************************/
192 KeyValue *
kvAdd(KeyValue * this,const Variant * key,const Variant * value)193 kvAdd(KeyValue *this, const Variant *key, const Variant *value)
194 {
195 FUNCTION_TEST_BEGIN();
196 FUNCTION_TEST_PARAM(KEY_VALUE, this);
197 FUNCTION_TEST_PARAM(VARIANT, key);
198 FUNCTION_TEST_PARAM(VARIANT, value);
199 FUNCTION_TEST_END();
200
201 ASSERT(this != NULL);
202 ASSERT(key != NULL);
203
204 MEM_CONTEXT_BEGIN(this->pub.memContext)
205 {
206 // Find the key
207 unsigned int listIdx = kvGetIdx(this, key);
208
209 // If the key was not found then add it
210 if (listIdx == KEY_NOT_FOUND)
211 {
212 kvPutInternal(this, key, varDup(value));
213 }
214 // Else create or add to the variant list
215 else
216 {
217 KeyValuePair *pair = (KeyValuePair *)lstGet(this->list, listIdx);
218
219 if (pair->value == NULL)
220 pair->value = varDup(value);
221 else if (varType(pair->value) != varTypeVariantList)
222 {
223 Variant *valueList = varNewVarLst(varLstNew());
224 varLstAdd(varVarLst(valueList), pair->value);
225 varLstAdd(varVarLst(valueList), varDup(value));
226 pair->value = valueList;
227 }
228 else
229 varLstAdd(varVarLst(pair->value), varDup(value));
230 }
231 }
232 MEM_CONTEXT_END();
233
234 FUNCTION_TEST_RETURN(this);
235 }
236
237 /**********************************************************************************************************************************/
238 KeyValue *
kvPutKv(KeyValue * this,const Variant * key)239 kvPutKv(KeyValue *this, const Variant *key)
240 {
241 FUNCTION_TEST_BEGIN();
242 FUNCTION_TEST_PARAM(KEY_VALUE, this);
243 FUNCTION_TEST_PARAM(VARIANT, key);
244 FUNCTION_TEST_END();
245
246 ASSERT(this != NULL);
247 ASSERT(key != NULL);
248
249 KeyValue *result = NULL;
250
251 MEM_CONTEXT_BEGIN(this->pub.memContext)
252 {
253 result = kvNew();
254 kvPutInternal(this, key, varNewKv(result));
255 }
256 MEM_CONTEXT_END();
257
258 FUNCTION_TEST_RETURN(result);
259 }
260
261 /**********************************************************************************************************************************/
262 const Variant *
kvGet(const KeyValue * this,const Variant * key)263 kvGet(const KeyValue *this, const Variant *key)
264 {
265 FUNCTION_TEST_BEGIN();
266 FUNCTION_TEST_PARAM(KEY_VALUE, this);
267 FUNCTION_TEST_PARAM(VARIANT, key);
268 FUNCTION_TEST_END();
269
270 ASSERT(this != NULL);
271 ASSERT(key != NULL);
272
273 Variant *result = NULL;
274
275 // Find the key
276 unsigned int listIdx = kvGetIdx(this, key);
277
278 if (listIdx != KEY_NOT_FOUND)
279 result = ((KeyValuePair *)lstGet(this->list, listIdx))->value;
280
281 FUNCTION_TEST_RETURN(result);
282 }
283
284 /**********************************************************************************************************************************/
285 const Variant *
kvGetDefault(const KeyValue * this,const Variant * key,const Variant * defaultValue)286 kvGetDefault(const KeyValue *this, const Variant *key, const Variant *defaultValue)
287 {
288 FUNCTION_TEST_BEGIN();
289 FUNCTION_TEST_PARAM(KEY_VALUE, this);
290 FUNCTION_TEST_PARAM(VARIANT, key);
291 FUNCTION_TEST_PARAM(VARIANT, defaultValue);
292 FUNCTION_TEST_END();
293
294 ASSERT(this != NULL);
295 ASSERT(key != NULL);
296
297 const Variant *result = NULL;
298
299 // Find the key
300 unsigned int listIdx = kvGetIdx(this, key);
301
302 // If key not found then return default, else return the value
303 if (listIdx == KEY_NOT_FOUND)
304 result = defaultValue;
305 else
306 result = ((KeyValuePair *)lstGet(this->list, listIdx))->value;
307
308 FUNCTION_TEST_RETURN(result);
309 }
310
311 /**********************************************************************************************************************************/
312 VariantList *
kvGetList(const KeyValue * this,const Variant * key)313 kvGetList(const KeyValue *this, const Variant *key)
314 {
315 FUNCTION_TEST_BEGIN();
316 FUNCTION_TEST_PARAM(KEY_VALUE, this);
317 FUNCTION_TEST_PARAM(VARIANT, key);
318 FUNCTION_TEST_END();
319
320 ASSERT(this != NULL);
321 ASSERT(key != NULL);
322
323 VariantList *result = NULL;
324
325 // Get the value
326 const Variant *value = kvGet(this, key);
327
328 // Convert the value to a list if it is not already one
329 if (value != NULL && varType(value) == varTypeVariantList)
330 result = varLstDup(varVarLst(value));
331 else
332 result = varLstAdd(varLstNew(), varDup(value));
333
334 FUNCTION_TEST_RETURN(result);
335 }
336