source: mainline/uspace/lib/bithenge/src/compound.c@ 1433ecda

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1433ecda was 84239b1, checked in by Jiri Svoboda <jiri@…>, 7 years ago

And there was much fixing.

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - 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 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bithenge
30 * @{
31 */
32/**
33 * @file
34 * Compound transforms.
35 */
36
37#include <stdlib.h>
38#include <bithenge/compound.h>
39#include <bithenge/expression.h>
40#include <bithenge/transform.h>
41#include <bithenge/tree.h>
42#include "common.h"
43
44
45
46/***************** compose_transform *****************/
47
48typedef struct {
49 bithenge_transform_t base;
50 bithenge_transform_t **xforms;
51 size_t num;
52} compose_transform_t;
53
54static bithenge_transform_t *compose_as_transform(compose_transform_t *xform)
55{
56 return &xform->base;
57}
58
59static compose_transform_t *transform_as_compose(bithenge_transform_t *xform)
60{
61 return (compose_transform_t *)xform;
62}
63
64static errno_t compose_apply(bithenge_transform_t *base, bithenge_scope_t *scope,
65 bithenge_node_t *in, bithenge_node_t **out)
66{
67 errno_t rc;
68 compose_transform_t *self = transform_as_compose(base);
69 bithenge_node_inc_ref(in);
70
71 /* i ranges from (self->num - 1) to 0 inside the loop. */
72 size_t i = self->num;
73 while (i-- != 0) {
74 bithenge_node_t *tmp;
75 rc = bithenge_transform_apply(self->xforms[i], scope, in,
76 &tmp);
77 bithenge_node_dec_ref(in);
78 if (rc != EOK)
79 return rc;
80 in = tmp;
81 }
82
83 *out = in;
84 return EOK;
85}
86
87static errno_t compose_prefix_length(bithenge_transform_t *base,
88 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
89{
90 compose_transform_t *self = transform_as_compose(base);
91 return bithenge_transform_prefix_length(self->xforms[self->num - 1],
92 scope, blob, out);
93}
94
95static void compose_destroy(bithenge_transform_t *base)
96{
97 compose_transform_t *self = transform_as_compose(base);
98 for (size_t i = 0; i < self->num; i++)
99 bithenge_transform_dec_ref(self->xforms[i]);
100 free(self->xforms);
101 free(self);
102}
103
104static const bithenge_transform_ops_t compose_transform_ops = {
105 .apply = compose_apply,
106 .prefix_length = compose_prefix_length,
107 .destroy = compose_destroy,
108};
109
110/** Create a composition of multiple transforms. When the result is applied to a
111 * node, each transform is applied in turn, with the last transform applied
112 * first. @a xforms may contain any number of transforms or no transforms at
113 * all. This function takes ownership of @a xforms and the references therein.
114 * @param[out] out Holds the result.
115 * @param[in] xforms The transforms to apply.
116 * @param num The number of transforms.
117 * @return EOK on success or an error code from errno.h. */
118errno_t bithenge_new_composed_transform(bithenge_transform_t **out,
119 bithenge_transform_t **xforms, size_t num)
120{
121 if (num == 0) {
122 /* TODO: optimize */
123 } else if (num == 1) {
124 *out = xforms[0];
125 free(xforms);
126 return EOK;
127 }
128
129 errno_t rc;
130 compose_transform_t *self = malloc(sizeof(*self));
131 if (!self) {
132 rc = ENOMEM;
133 goto error;
134 }
135 rc = bithenge_init_transform(compose_as_transform(self),
136 &compose_transform_ops, 0);
137 if (rc != EOK)
138 goto error;
139 self->xforms = xforms;
140 self->num = num;
141 *out = compose_as_transform(self);
142 return EOK;
143error:
144 for (size_t i = 0; i < num; i++)
145 bithenge_transform_dec_ref(xforms[i]);
146 free(xforms);
147 free(self);
148 return rc;
149}
150
151
152
153/***************** if_transform *****************/
154
155typedef struct {
156 bithenge_transform_t base;
157 bithenge_expression_t *expr;
158 bithenge_transform_t *true_xform, *false_xform;
159} if_transform_t;
160
161static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
162{
163 return &self->base;
164}
165
166static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
167{
168 return (if_transform_t *)base;
169}
170
171static errno_t if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
172 bool *out)
173{
174 bithenge_node_t *cond_node;
175 errno_t rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
176 if (rc != EOK)
177 return rc;
178 if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
179 bithenge_node_dec_ref(cond_node);
180 return EINVAL;
181 }
182 *out = bithenge_boolean_node_value(cond_node);
183 bithenge_node_dec_ref(cond_node);
184 return EOK;
185}
186
187static errno_t if_transform_apply(bithenge_transform_t *base,
188 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
189{
190 if_transform_t *self = transform_as_if(base);
191 bool cond;
192 errno_t rc = if_transform_choose(self, scope, &cond);
193 if (rc != EOK)
194 return rc;
195 return bithenge_transform_apply(
196 cond ? self->true_xform : self->false_xform, scope, in, out);
197}
198
199static errno_t if_transform_prefix_length(bithenge_transform_t *base,
200 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
201{
202 if_transform_t *self = transform_as_if(base);
203 bool cond;
204 errno_t rc = if_transform_choose(self, scope, &cond);
205 if (rc != EOK)
206 return rc;
207 return bithenge_transform_prefix_length(
208 cond ? self->true_xform : self->false_xform, scope, in, out);
209}
210
211static void if_transform_destroy(bithenge_transform_t *base)
212{
213 if_transform_t *self = transform_as_if(base);
214 bithenge_expression_dec_ref(self->expr);
215 bithenge_transform_dec_ref(self->true_xform);
216 bithenge_transform_dec_ref(self->false_xform);
217 free(self);
218}
219
220static const bithenge_transform_ops_t if_transform_ops = {
221 .apply = if_transform_apply,
222 .prefix_length = if_transform_prefix_length,
223 .destroy = if_transform_destroy,
224};
225
226/** Create a transform that applies either of two transforms depending on a
227 * boolean expression. Takes references to @a expr, @a true_xform, and
228 * @a false_xform.
229 * @param[out] out Holds the new transform.
230 * @param expr The boolean expression to evaluate.
231 * @param true_xform The transform to apply if the expression is true.
232 * @param false_xform The transform to apply if the expression is false.
233 * @return EOK on success or an error code from errno.h. */
234errno_t bithenge_if_transform(bithenge_transform_t **out,
235 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
236 bithenge_transform_t *false_xform)
237{
238 errno_t rc;
239 if_transform_t *self = malloc(sizeof(*self));
240 if (!self) {
241 rc = ENOMEM;
242 goto error;
243 }
244
245 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
246 0);
247 if (rc != EOK)
248 goto error;
249
250 self->expr = expr;
251 self->true_xform = true_xform;
252 self->false_xform = false_xform;
253 *out = if_as_transform(self);
254 return EOK;
255
256error:
257 free(self);
258 bithenge_expression_dec_ref(expr);
259 bithenge_transform_dec_ref(true_xform);
260 bithenge_transform_dec_ref(false_xform);
261 return rc;
262}
263
264
265
266/***************** partial_transform *****************/
267
268typedef struct {
269 bithenge_transform_t base;
270 bithenge_transform_t *xform;
271} partial_transform_t;
272
273static inline bithenge_transform_t *partial_as_transform(
274 partial_transform_t *self)
275{
276 return &self->base;
277}
278
279static inline partial_transform_t *transform_as_partial(
280 bithenge_transform_t *base)
281{
282 return (partial_transform_t *)base;
283}
284
285static errno_t partial_transform_apply(bithenge_transform_t *base,
286 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
287{
288 partial_transform_t *self = transform_as_partial(base);
289 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
290 return EINVAL;
291 return bithenge_transform_prefix_apply(self->xform, scope,
292 bithenge_node_as_blob(in), out, NULL);
293}
294
295static void partial_transform_destroy(bithenge_transform_t *base)
296{
297 partial_transform_t *self = transform_as_partial(base);
298 bithenge_transform_dec_ref(self->xform);
299 free(self);
300}
301
302static const bithenge_transform_ops_t partial_transform_ops = {
303 .apply = partial_transform_apply,
304 .destroy = partial_transform_destroy,
305};
306
307/** Create a transform that doesn't require its subtransform to use the whole
308 * input. Takes a reference to @a xform.
309 * @param[out] out Holds the new transform.
310 * @param xform The subtransform to apply.
311 * @return EOK on success or an error code from errno.h. */
312errno_t bithenge_partial_transform(bithenge_transform_t **out,
313 bithenge_transform_t *xform)
314{
315 errno_t rc;
316 partial_transform_t *self = malloc(sizeof(*self));
317 if (!self) {
318 rc = ENOMEM;
319 goto error;
320 }
321
322 rc = bithenge_init_transform(partial_as_transform(self),
323 &partial_transform_ops, 0);
324 if (rc != EOK)
325 goto error;
326
327 self->xform = xform;
328 *out = partial_as_transform(self);
329 return EOK;
330
331error:
332 free(self);
333 bithenge_transform_dec_ref(xform);
334 return rc;
335}
336
337/** @}
338 */
Note: See TracBrowser for help on using the repository browser.