BadVPN – Blame information for rev 1
?pathlinks?
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 | } |