source: mainline/uspace/app/bithenge/compound.c@ 6be4142

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6be4142 was c54f5d0, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

Bithenge: partial transforms

  • Property mode set to 100644
File size: 9.3 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 "compound.h"
39#include "expression.h"
40#include "transform.h"
41#include "tree.h"
42
43
44
45/***************** compose_transform *****************/
46
47typedef struct {
48 bithenge_transform_t base;
49 bithenge_transform_t **xforms;
50 size_t num;
51} compose_transform_t;
52
53static bithenge_transform_t *compose_as_transform(compose_transform_t *xform)
54{
55 return &xform->base;
56}
57
58static compose_transform_t *transform_as_compose(bithenge_transform_t *xform)
59{
60 return (compose_transform_t *)xform;
61}
62
63static int compose_apply(bithenge_transform_t *base, bithenge_scope_t *scope,
64 bithenge_node_t *in, bithenge_node_t **out)
65{
66 int rc;
67 compose_transform_t *self = transform_as_compose(base);
68 bithenge_node_inc_ref(in);
69
70 /* i ranges from (self->num - 1) to 0 inside the loop. */
71 for (size_t i = self->num; i--; ) {
72 bithenge_node_t *tmp;
73 rc = bithenge_transform_apply(self->xforms[i], scope, in,
74 &tmp);
75 bithenge_node_dec_ref(in);
76 if (rc != EOK)
77 return rc;
78 in = tmp;
79 }
80
81 *out = in;
82 return rc;
83}
84
85static int compose_prefix_length(bithenge_transform_t *base,
86 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
87{
88 compose_transform_t *self = transform_as_compose(base);
89 return bithenge_transform_prefix_length(self->xforms[self->num - 1],
90 scope, blob, out);
91}
92
93static void compose_destroy(bithenge_transform_t *base)
94{
95 compose_transform_t *self = transform_as_compose(base);
96 for (size_t i = 0; i < self->num; i++)
97 bithenge_transform_dec_ref(self->xforms[i]);
98 free(self->xforms);
99 free(self);
100}
101
102static const bithenge_transform_ops_t compose_transform_ops = {
103 .apply = compose_apply,
104 .prefix_length = compose_prefix_length,
105 .destroy = compose_destroy,
106};
107
108/** Create a composition of multiple transforms. When the result is applied to a
109 * node, each transform is applied in turn, with the last transform applied
110 * first. @a xforms may contain any number of transforms or no transforms at
111 * all. This function takes ownership of @a xforms and the references therein.
112 * @param[out] out Holds the result.
113 * @param[in] xforms The transforms to apply.
114 * @param num The number of transforms.
115 * @return EOK on success or an error code from errno.h. */
116int bithenge_new_composed_transform(bithenge_transform_t **out,
117 bithenge_transform_t **xforms, size_t num)
118{
119 if (num == 0) {
120 /* TODO: optimize */
121 } else if (num == 1) {
122 *out = xforms[0];
123 free(xforms);
124 return EOK;
125 }
126
127 int rc;
128 compose_transform_t *self = malloc(sizeof(*self));
129 if (!self) {
130 rc = ENOMEM;
131 goto error;
132 }
133 rc = bithenge_init_transform(compose_as_transform(self),
134 &compose_transform_ops, 0);
135 if (rc != EOK)
136 goto error;
137 self->xforms = xforms;
138 self->num = num;
139 *out = compose_as_transform(self);
140 return EOK;
141error:
142 for (size_t i = 0; i < num; i++)
143 bithenge_transform_dec_ref(xforms[i]);
144 free(xforms);
145 free(self);
146 return rc;
147}
148
149
150
151/***************** if_transform *****************/
152
153typedef struct {
154 bithenge_transform_t base;
155 bithenge_expression_t *expr;
156 bithenge_transform_t *true_xform, *false_xform;
157} if_transform_t;
158
159static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
160{
161 return &self->base;
162}
163
164static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
165{
166 return (if_transform_t *)base;
167}
168
169static int if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
170 bool *out)
171{
172 bithenge_node_t *cond_node;
173 int rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
174 if (rc != EOK)
175 return rc;
176 if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
177 bithenge_node_dec_ref(cond_node);
178 return EINVAL;
179 }
180 *out = bithenge_boolean_node_value(cond_node);
181 bithenge_node_dec_ref(cond_node);
182 return EOK;
183}
184
185static int if_transform_apply(bithenge_transform_t *base,
186 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
187{
188 if_transform_t *self = transform_as_if(base);
189 bool cond;
190 int rc = if_transform_choose(self, scope, &cond);
191 if (rc != EOK)
192 return rc;
193 return bithenge_transform_apply(
194 cond ? self->true_xform : self->false_xform, scope, in, out);
195}
196
197static int if_transform_prefix_length(bithenge_transform_t *base,
198 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
199{
200 if_transform_t *self = transform_as_if(base);
201 bool cond;
202 int rc = if_transform_choose(self, scope, &cond);
203 if (rc != EOK)
204 return rc;
205 return bithenge_transform_prefix_length(
206 cond ? self->true_xform : self->false_xform, scope, in, out);
207}
208
209static void if_transform_destroy(bithenge_transform_t *base)
210{
211 if_transform_t *self = transform_as_if(base);
212 bithenge_expression_dec_ref(self->expr);
213 bithenge_transform_dec_ref(self->true_xform);
214 bithenge_transform_dec_ref(self->false_xform);
215 free(self);
216}
217
218static const bithenge_transform_ops_t if_transform_ops = {
219 .apply = if_transform_apply,
220 .prefix_length = if_transform_prefix_length,
221 .destroy = if_transform_destroy,
222};
223
224/** Create a transform that applies either of two transforms depending on a
225 * boolean expression. Takes references to @a expr, @a true_xform, and
226 * @a false_xform.
227 * @param[out] out Holds the new transform.
228 * @param expr The boolean expression to evaluate.
229 * @param true_xform The transform to apply if the expression is true.
230 * @param false_xform The transform to apply if the expression is false.
231 * @return EOK on success or an error code from errno.h. */
232int bithenge_if_transform(bithenge_transform_t **out,
233 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
234 bithenge_transform_t *false_xform)
235{
236 int rc;
237 if_transform_t *self = malloc(sizeof(*self));
238 if (!self) {
239 rc = ENOMEM;
240 goto error;
241 }
242
243 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
244 0);
245 if (rc != EOK)
246 goto error;
247
248 self->expr = expr;
249 self->true_xform = true_xform;
250 self->false_xform = false_xform;
251 *out = if_as_transform(self);
252 return EOK;
253
254error:
255 free(self);
256 bithenge_expression_dec_ref(expr);
257 bithenge_transform_dec_ref(true_xform);
258 bithenge_transform_dec_ref(false_xform);
259 return rc;
260}
261
262
263
264/***************** partial_transform *****************/
265
266typedef struct {
267 bithenge_transform_t base;
268 bithenge_transform_t *xform;
269} partial_transform_t;
270
271static inline bithenge_transform_t *partial_as_transform(
272 partial_transform_t *self)
273{
274 return &self->base;
275}
276
277static inline partial_transform_t *transform_as_partial(
278 bithenge_transform_t *base)
279{
280 return (partial_transform_t *)base;
281}
282
283static int partial_transform_apply(bithenge_transform_t *base,
284 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
285{
286 partial_transform_t *self = transform_as_partial(base);
287 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
288 return EINVAL;
289 uint64_t size;
290 return bithenge_transform_prefix_apply(self->xform, scope,
291 bithenge_node_as_blob(in), out, &size);
292}
293
294static void partial_transform_destroy(bithenge_transform_t *base)
295{
296 partial_transform_t *self = transform_as_partial(base);
297 bithenge_transform_dec_ref(self->xform);
298 free(self);
299}
300
301static const bithenge_transform_ops_t partial_transform_ops = {
302 .apply = partial_transform_apply,
303 .destroy = partial_transform_destroy,
304};
305
306/** Create a transform that doesn't require its subtransform to use the whole
307 * input. Takes a reference to @a xform.
308 * @param[out] out Holds the new transform.
309 * @param xform The subtransform to apply.
310 * @return EOK on success or an error code from errno.h. */
311int bithenge_partial_transform(bithenge_transform_t **out,
312 bithenge_transform_t *xform)
313{
314 int rc;
315 partial_transform_t *self = malloc(sizeof(*self));
316 if (!self) {
317 rc = ENOMEM;
318 goto error;
319 }
320
321 rc = bithenge_init_transform(partial_as_transform(self),
322 &partial_transform_ops, 0);
323 if (rc != EOK)
324 goto error;
325
326 self->xform = xform;
327 *out = partial_as_transform(self);
328 return EOK;
329
330error:
331 free(self);
332 bithenge_transform_dec_ref(xform);
333 return rc;
334}
335
336/** @}
337 */
Note: See TracBrowser for help on using the repository browser.