BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file NCDValCons.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <misc/balloc.h>
31  
32 #include "NCDValCons.h"
33  
34 #define GROWARRAY_NAME NCDValCons__Array
35 #define GROWARRAY_OBJECT_TYPE NCDValCons
36 #define GROWARRAY_ARRAY_MEMBER elems
37 #define GROWARRAY_CAPACITY_MEMBER elems_capacity
38 #define GROWARRAY_MAX_CAPACITY INT_MAX
39 #include <misc/grow_array.h>
40  
41 static int alloc_elem (NCDValCons *o)
42 {
43 ASSERT(o->elems_size >= 0)
44 ASSERT(o->elems_size <= o->elems_capacity)
45  
46 if (o->elems_size == o->elems_capacity && !NCDValCons__Array_DoubleUp(o)) {
47 return -1;
48 }
49  
50 return o->elems_size++;
51 }
52  
53 static void assert_cons_val (NCDValCons *o, NCDValConsVal val)
54 {
55 #ifndef NDEBUG
56 switch (val.cons_type) {
57 case NCDVALCONS_TYPE_COMPLETE: {
58 ASSERT(!NCDVal_IsInvalid(NCDVal_FromSafe(o->mem, val.u.complete_ref)))
59 } break;
60 case NCDVALCONS_TYPE_INCOMPLETE_LIST:
61 case NCDVALCONS_TYPE_INCOMPLETE_MAP: {
62 ASSERT(val.u.incomplete.elems_idx >= -1)
63 ASSERT(val.u.incomplete.elems_idx < o->elems_size)
64 ASSERT(val.u.incomplete.count >= 0)
65 } break;
66 default:
67 ASSERT(0);
68 }
69 #endif
70 }
71  
72 static int complete_value (NCDValCons *o, NCDValConsVal val, NCDValSafeRef *out, int *out_error)
73 {
74 assert_cons_val(o, val);
75 ASSERT(out)
76 ASSERT(out_error)
77  
78 switch (val.cons_type) {
79 case NCDVALCONS_TYPE_COMPLETE: {
80 *out = val.u.complete_ref;
81 } break;
82  
83 case NCDVALCONS_TYPE_INCOMPLETE_LIST: {
84 NCDValRef list = NCDVal_NewList(o->mem, val.u.incomplete.count);
85 if (NCDVal_IsInvalid(list)) {
86 goto fail_memory;
87 }
88  
89 int elemidx = val.u.incomplete.elems_idx;
90  
91 while (elemidx != -1) {
92 ASSERT(elemidx >= 0)
93 ASSERT(elemidx < o->elems_size)
94  
95 NCDValRef elem = NCDVal_FromSafe(o->mem, o->elems[elemidx].ref);
96  
97 if (!NCDVal_ListAppend(list, elem)) {
98 *out_error = NCDVALCONS_ERROR_DEPTH;
99 return 0;
100 }
101  
102 elemidx = o->elems[elemidx].next;
103 }
104  
105 *out = NCDVal_ToSafe(list);
106 } break;
107  
108 case NCDVALCONS_TYPE_INCOMPLETE_MAP: {
109 NCDValRef map = NCDVal_NewMap(o->mem, val.u.incomplete.count);
110 if (NCDVal_IsInvalid(map)) {
111 goto fail_memory;
112 }
113  
114 int keyidx = val.u.incomplete.elems_idx;
115  
116 while (keyidx != -1) {
117 ASSERT(keyidx >= 0)
118 ASSERT(keyidx < o->elems_size)
119  
120 int validx = o->elems[keyidx].next;
121 ASSERT(validx >= 0)
122 ASSERT(validx < o->elems_size)
123  
124 NCDValRef key = NCDVal_FromSafe(o->mem, o->elems[keyidx].ref);
125 NCDValRef value = NCDVal_FromSafe(o->mem, o->elems[validx].ref);
126  
127 int inserted;
128 if (!NCDVal_MapInsert(map, key, value, &inserted)) {
129 *out_error = NCDVALCONS_ERROR_DEPTH;
130 return 0;
131 }
132 if (!inserted) {
133 *out_error = NCDVALCONS_ERROR_DUPLICATE_KEY;
134 return 0;
135 }
136  
137 keyidx = o->elems[validx].next;
138 }
139  
140 *out = NCDVal_ToSafe(map);
141 } break;
142  
143 default:
144 ASSERT(0);
145 }
146  
147 return 1;
148  
149 fail_memory:
150 *out_error = NCDVALCONS_ERROR_MEMORY;
151 return 0;
152 }
153  
154 int NCDValCons_Init (NCDValCons *o, NCDValMem *mem)
155 {
156 ASSERT(mem)
157  
158 o->mem = mem;
159 o->elems_size = 0;
160  
161 if (!NCDValCons__Array_Init(o, 1)) {
162 return 0;
163 }
164  
165 return 1;
166 }
167  
168 void NCDValCons_Free (NCDValCons *o)
169 {
170 NCDValCons__Array_Free(o);
171 }
172  
173 int NCDValCons_NewString (NCDValCons *o, const uint8_t *data, size_t len, NCDValConsVal *out, int *out_error)
174 {
175 ASSERT(out)
176 ASSERT(out_error)
177  
178 NCDValRef ref = NCDVal_NewStringBin(o->mem, data, len);
179 if (NCDVal_IsInvalid(ref)) {
180 *out_error = NCDVALCONS_ERROR_MEMORY;
181 return 0;
182 }
183  
184 out->cons_type = NCDVALCONS_TYPE_COMPLETE;
185 out->u.complete_ref = NCDVal_ToSafe(ref);
186  
187 return 1;
188 }
189  
190 void NCDValCons_NewList (NCDValCons *o, NCDValConsVal *out)
191 {
192 ASSERT(out)
193  
194 out->cons_type = NCDVALCONS_TYPE_INCOMPLETE_LIST;
195 out->u.incomplete.elems_idx = -1;
196 out->u.incomplete.count = 0;
197 }
198  
199 void NCDValCons_NewMap (NCDValCons *o, NCDValConsVal *out)
200 {
201 ASSERT(out)
202  
203 out->cons_type = NCDVALCONS_TYPE_INCOMPLETE_MAP;
204 out->u.incomplete.elems_idx = -1;
205 out->u.incomplete.count = 0;
206 }
207  
208 int NCDValCons_ListPrepend (NCDValCons *o, NCDValConsVal *list, NCDValConsVal elem, int *out_error)
209 {
210 assert_cons_val(o, *list);
211 ASSERT(list->cons_type == NCDVALCONS_TYPE_INCOMPLETE_LIST)
212 assert_cons_val(o, elem);
213 ASSERT(out_error)
214  
215 int elemidx = alloc_elem(o);
216 if (elemidx < 0) {
217 *out_error = NCDVALCONS_ERROR_MEMORY;
218 return 0;
219 }
220  
221 o->elems[elemidx].next = list->u.incomplete.elems_idx;
222  
223 if (!complete_value(o, elem, &o->elems[elemidx].ref, out_error)) {
224 return 0;
225 }
226  
227 list->u.incomplete.elems_idx = elemidx;
228 list->u.incomplete.count++;
229  
230 return 1;
231 }
232  
233 int NCDValCons_MapInsert (NCDValCons *o, NCDValConsVal *map, NCDValConsVal key, NCDValConsVal value, int *out_error)
234 {
235 assert_cons_val(o, *map);
236 ASSERT(map->cons_type == NCDVALCONS_TYPE_INCOMPLETE_MAP)
237 assert_cons_val(o, key);
238 assert_cons_val(o, value);
239 ASSERT(out_error)
240  
241 int validx = alloc_elem(o);
242 if (validx < 0) {
243 *out_error = NCDVALCONS_ERROR_MEMORY;
244 return 0;
245 }
246  
247 int keyidx = alloc_elem(o);
248 if (keyidx < 0) {
249 *out_error = NCDVALCONS_ERROR_MEMORY;
250 return 0;
251 }
252  
253 o->elems[validx].next = map->u.incomplete.elems_idx;
254 o->elems[keyidx].next = validx;
255  
256 if (!complete_value(o, value, &o->elems[validx].ref, out_error)) {
257 return 0;
258 }
259  
260 if (!complete_value(o, key, &o->elems[keyidx].ref, out_error)) {
261 return 0;
262 }
263  
264 map->u.incomplete.elems_idx = keyidx;
265 map->u.incomplete.count++;
266  
267 return 1;
268 }
269  
270 int NCDValCons_Complete (NCDValCons *o, NCDValConsVal val, NCDValRef *out, int *out_error)
271 {
272 assert_cons_val(o, val);
273 ASSERT(out)
274 ASSERT(out_error)
275  
276 NCDValSafeRef sref;
277 if (!complete_value(o, val, &sref, out_error)) {
278 return 0;
279 }
280  
281 *out = NCDVal_FromSafe(o->mem, sref);
282 return 1;
283 }