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