LP-89 - Port OP_15.05.01 fixes. Release notes:
[librepilot.git] / flight / libraries / PyMite / vm / dict.c
blob31b5d30e951481af21c40a2f4449381f740e721c
1 /*
2 # This file is Copyright 2003, 2006, 2007, 2009, 2010 Dean Hall.
4 # This file is part of the PyMite VM.
5 # The PyMite VM is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2.
8 # The PyMite VM is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # A copy of the GNU GENERAL PUBLIC LICENSE Version 2
12 # is seen in the file COPYING in this directory.
16 #undef __FILE_ID__
17 #define __FILE_ID__ 0x02
20 /**
21 * \file
22 * \brief Dict Object Type
24 * Dict object type operations.
28 #include "pm.h"
31 PmReturn_t
32 dict_new(pPmObj_t *r_pdict)
34 PmReturn_t retval = PM_RET_OK;
35 pPmDict_t pdict = C_NULL;
36 uint8_t *pchunk;
38 /* Allocate a dict */
39 retval = heap_getChunk(sizeof(PmDict_t), &pchunk);
40 PM_RETURN_IF_ERROR(retval);
42 /* Init dict fields */
43 pdict = (pPmDict_t)pchunk;
44 OBJ_SET_TYPE(pdict, OBJ_TYPE_DIC);
45 pdict->length = 0;
46 pdict->d_keys = C_NULL;
47 pdict->d_vals = C_NULL;
49 *r_pdict = (pPmObj_t)pchunk;
50 return retval;
54 PmReturn_t
55 dict_clear(pPmObj_t pdict)
57 PmReturn_t retval = PM_RET_OK;
59 C_ASSERT(pdict != C_NULL);
61 /* Raise TypeError if arg is not a dict */
62 if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC)
64 PM_RAISE(retval, PM_RET_EX_TYPE);
65 return retval;
68 /* clear length */
69 ((pPmDict_t)pdict)->length = 0;
71 /* Free the keys and values seglists if needed */
72 if (((pPmDict_t)pdict)->d_keys != C_NULL)
74 PM_RETURN_IF_ERROR(seglist_clear(((pPmDict_t)pdict)->d_keys));
75 PM_RETURN_IF_ERROR(heap_freeChunk((pPmObj_t)
76 ((pPmDict_t)pdict)->d_keys));
77 ((pPmDict_t)pdict)->d_keys = C_NULL;
79 if (((pPmDict_t)pdict)->d_vals != C_NULL)
81 PM_RETURN_IF_ERROR(seglist_clear(((pPmDict_t)pdict)->d_vals));
82 retval = heap_freeChunk((pPmObj_t)((pPmDict_t)pdict)->d_vals);
83 ((pPmDict_t)pdict)->d_vals = C_NULL;
85 return retval;
90 * Sets a value in the dict using the given key.
92 * Scans dict for the key. If key val found, replace old
93 * with new val. If no key found, add key/val pair to dict.
95 PmReturn_t
96 dict_setItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t pval)
98 PmReturn_t retval = PM_RET_OK;
99 int16_t indx;
101 C_ASSERT(pdict != C_NULL);
102 C_ASSERT(pkey != C_NULL);
103 C_ASSERT(pval != C_NULL);
105 /* If it's not a dict, raise TypeError */
106 if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC)
108 PM_RAISE(retval, PM_RET_EX_TYPE);
109 return retval;
112 /* #112: Force Dict keys to be of hashable type */
113 /* If key is not hashable, raise TypeError */
114 if (OBJ_GET_TYPE(pkey) > OBJ_TYPE_HASHABLE_MAX)
116 PM_RAISE(retval, PM_RET_EX_TYPE);
117 return retval;
120 /* #147: Change boolean keys to integers */
121 if (pkey == PM_TRUE)
123 pkey = PM_ONE;
125 else if (pkey == PM_FALSE)
127 pkey = PM_ZERO;
131 * #115: If this is the first key/value pair to be added to the Dict,
132 * allocate the key and value seglists that hold those items
134 if (((pPmDict_t)pdict)->length == 0)
136 retval = seglist_new(&((pPmDict_t)pdict)->d_keys);
137 PM_RETURN_IF_ERROR(retval);
138 retval = seglist_new(&((pPmDict_t)pdict)->d_vals);
139 PM_RETURN_IF_ERROR(retval);
141 else
143 /* Check for matching key */
144 indx = 0;
145 retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx);
147 /* If found a matching key, replace val obj */
148 if (retval == PM_RET_OK)
150 retval = seglist_setItem(((pPmDict_t)pdict)->d_vals, pval, indx);
151 return retval;
155 /* Otherwise, insert the key,val pair */
156 retval = seglist_insertItem(((pPmDict_t)pdict)->d_keys, pkey, 0);
157 PM_RETURN_IF_ERROR(retval);
158 retval = seglist_insertItem(((pPmDict_t)pdict)->d_vals, pval, 0);
159 ((pPmDict_t)pdict)->length++;
161 return retval;
165 PmReturn_t
166 dict_getItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t *r_pobj)
168 PmReturn_t retval = PM_RET_OK;
169 int16_t indx = 0;
171 /* C_ASSERT(pdict != C_NULL);*/
173 /* if it's not a dict, raise TypeError */
174 if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC)
176 PM_RAISE(retval, PM_RET_EX_TYPE);
177 return retval;
180 /* if dict is empty, raise KeyError */
181 if (((pPmDict_t)pdict)->length <= 0)
183 PM_RAISE(retval, PM_RET_EX_KEY);
184 return retval;
187 /* #147: Change boolean keys to integers */
188 if (pkey == PM_TRUE)
190 pkey = PM_ONE;
192 else if (pkey == PM_FALSE)
194 pkey = PM_ZERO;
197 /* check for matching key */
198 retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx);
199 /* if key not found, raise KeyError */
200 if (retval == PM_RET_NO)
202 PM_RAISE(retval, PM_RET_EX_KEY);
204 /* return any other error */
205 PM_RETURN_IF_ERROR(retval);
207 /* key was found, get obj from vals */
208 retval = seglist_getItem(((pPmDict_t)pdict)->d_vals, indx, r_pobj);
209 return retval;
213 #ifdef HAVE_DEL
214 PmReturn_t
215 dict_delItem(pPmObj_t pdict, pPmObj_t pkey)
217 PmReturn_t retval = PM_RET_OK;
218 int16_t indx = 0;
220 C_ASSERT(pdict != C_NULL);
222 /* Check for matching key */
223 retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx);
225 /* Raise KeyError if key is not found */
226 if (retval == PM_RET_NO)
228 PM_RAISE(retval, PM_RET_EX_KEY);
231 /* Return any other error */
232 PM_RETURN_IF_ERROR(retval);
234 /* Remove the key and value */
235 retval = seglist_removeItem(((pPmDict_t)pdict)->d_keys, indx);
236 PM_RETURN_IF_ERROR(retval);
237 retval = seglist_removeItem(((pPmDict_t)pdict)->d_vals, indx);
239 /* Reduce the item count */
240 ((pPmDict_t)pdict)->length--;
242 return retval;
244 #endif /* HAVE_DEL */
247 #ifdef HAVE_PRINT
248 PmReturn_t
249 dict_print(pPmObj_t pdict)
251 PmReturn_t retval = PM_RET_OK;
252 int16_t index;
253 pSeglist_t keys,
254 vals;
255 pPmObj_t pobj1;
257 C_ASSERT(pdict != C_NULL);
259 /* if it's not a dict, raise TypeError */
260 if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC)
262 PM_RAISE(retval, PM_RET_EX_TYPE);
263 return retval;
266 plat_putByte('{');
268 keys = ((pPmDict_t)pdict)->d_keys;
269 vals = ((pPmDict_t)pdict)->d_vals;
271 /* if dict is empty, raise KeyError */
272 for (index = 0; index < ((pPmDict_t)pdict)->length; index++)
274 if (index != 0)
276 plat_putByte(',');
277 plat_putByte(' ');
279 retval = seglist_getItem(keys, index, &pobj1);
280 PM_RETURN_IF_ERROR(retval);
281 retval = obj_print(pobj1, C_FALSE, C_TRUE);
282 PM_RETURN_IF_ERROR(retval);
284 plat_putByte(':');
285 retval = seglist_getItem(vals, index, &pobj1);
286 PM_RETURN_IF_ERROR(retval);
287 retval = obj_print(pobj1, C_FALSE, C_TRUE);
288 PM_RETURN_IF_ERROR(retval);
291 return plat_putByte('}');
293 #endif /* HAVE_PRINT */
295 PmReturn_t
296 dict_update(pPmObj_t pdestdict, pPmObj_t psourcedict)
298 PmReturn_t retval = PM_RET_OK;
299 int16_t i;
300 pPmObj_t pkey;
301 pPmObj_t pval;
303 C_ASSERT(pdestdict != C_NULL);
304 C_ASSERT(psourcedict != C_NULL);
306 /* If it's not a dict, raise TypeError */
307 if (OBJ_GET_TYPE(pdestdict) != OBJ_TYPE_DIC)
309 PM_RAISE(retval, PM_RET_EX_TYPE);
310 return retval;
313 /* If it's not a dict, raise TypeError */
314 if (OBJ_GET_TYPE(psourcedict) != OBJ_TYPE_DIC)
316 PM_RAISE(retval, PM_RET_EX_TYPE);
317 return retval;
320 /* Iterate over the add-on dict */
321 for (i = 0; i < ((pPmDict_t)psourcedict)->length; i++)
323 /* Get the key,val from the add-on dict */
324 retval = seglist_getItem(((pPmDict_t)psourcedict)->d_keys, i, &pkey);
325 PM_RETURN_IF_ERROR(retval);
326 retval = seglist_getItem(((pPmDict_t)psourcedict)->d_vals, i, &pval);
327 PM_RETURN_IF_ERROR(retval);
329 /* Set the key,val to the destination dict */
330 retval = dict_setItem(pdestdict, pkey, pval);
331 PM_RETURN_IF_ERROR(retval);
334 return retval;