source: mainline/uspace/lib/bithenge/src/compound.c@ 2ee05261

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2ee05261 was 8fc0f47c, checked in by Vojtech Horky <vojtechhorky@…>, 13 years ago

Clean Bithenge headers namespace

Move headers into <bithenge/>, put sources into src/.

  • 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/os.h>
41#include <bithenge/transform.h>
42#include <bithenge/tree.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 int compose_apply(bithenge_transform_t *base, bithenge_scope_t *scope,
65 bithenge_node_t *in, bithenge_node_t **out)
66{
67 int 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 for (size_t i = self->num; i--; ) {
73 bithenge_node_t *tmp;
74 rc = bithenge_transform_apply(self->xforms[i], scope, in,
75 &tmp);
76 bithenge_node_dec_ref(in);
77 if (rc != EOK)
78 return rc;
79 in = tmp;
80 }
81
82 *out = in;
83 return rc;
84}
85
86static int compose_prefix_length(bithenge_transform_t *base,
87 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
88{
89 compose_transform_t *self = transform_as_compose(base);
90 return bithenge_transform_prefix_length(self->xforms[self->num - 1],
91 scope, blob, out);
92}
93
94static void compose_destroy(bithenge_transform_t *base)
95{
96 compose_transform_t *self = transform_as_compose(base);
97 for (size_t i = 0; i < self->num; i++)
98 bithenge_transform_dec_ref(self->xforms[i]);
99 free(self->xforms);
100 free(self);
101}
102
103static const bithenge_transform_ops_t compose_transform_ops = {
104 .apply = compose_apply,
105 .prefix_length = compose_prefix_length,
106 .destroy = compose_destroy,
107};
108
109/** Create a composition of multiple transforms. When the result is applied to a
110 * node, each transform is applied in turn, with the last transform applied
111 * first. @a xforms may contain any number of transforms or no transforms at
112 * all. This function takes ownership of @a xforms and the references therein.
113 * @param[out] out Holds the result.
114 * @param[in] xforms The transforms to apply.
115 * @param num The number of transforms.
116 * @return EOK on success or an error code from errno.h. */
117int bithenge_new_composed_transform(bithenge_transform_t **out,
118 bithenge_transform_t **xforms, size_t num)
119{
120 if (num == 0) {
121 /* TODO: optimize */
122 } else if (num == 1) {
123 *out = xforms[0];
124 free(xforms);
125 return EOK;
126 }
127
128 int rc;
129 compose_transform_t *self = malloc(sizeof(*self));
130 if (!self) {
131 rc = ENOMEM;
132 goto error;
133 }
134 rc = bithenge_init_transform(compose_as_transform(self),
135 &compose_transform_ops, 0);
136 if (rc != EOK)
137 goto error;
138 self->xforms = xforms;
139 self->num = num;
140 *out = compose_as_transform(self);
141 return EOK;
142error:
143 for (size_t i = 0; i < num; i++)
144 bithenge_transform_dec_ref(xforms[i]);
145 free(xforms);
146 free(self);
147 return rc;
148}
149
150
151
152/***************** if_transform *****************/
153
154typedef struct {
155 bithenge_transform_t base;
156 bithenge_expression_t *expr;
157 bithenge_transform_t *true_xform, *false_xform;
158} if_transform_t;
159
160static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
161{
162 return &self->base;
163}
164
165static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
166{
167 return (if_transform_t *)base;
168}
169
170static int if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
171 bool *out)
172{
173 bithenge_node_t *cond_node;
174 int rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
175 if (rc != EOK)
176 return rc;
177 if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
178 bithenge_node_dec_ref(cond_node);
179 return EINVAL;
180 }
181 *out = bithenge_boolean_node_value(cond_node);
182 bithenge_node_dec_ref(cond_node);
183 return EOK;
184}
185
186static int if_transform_apply(bithenge_transform_t *base,
187 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
188{
189 if_transform_t *self = transform_as_if(base);
190 bool cond;
191 int rc = if_transform_choose(self, scope, &cond);
192 if (rc != EOK)
193 return rc;
194 return bithenge_transform_apply(
195 cond ? self->true_xform : self->false_xform, scope, in, out);
196}
197
198static int if_transform_prefix_length(bithenge_transform_t *base,
199 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
200{
201 if_transform_t *self = transform_as_if(base);
202 bool cond;
203 int rc = if_transform_choose(self, scope, &cond);
204 if (rc != EOK)
205 return rc;
206 return bithenge_transform_prefix_length(
207 cond ? self->true_xform : self->false_xform, scope, in, out);
208}
209
210static void if_transform_destroy(bithenge_transform_t *base)
211{
212 if_transform_t *self = transform_as_if(base);
213 bithenge_expression_dec_ref(self->expr);
214 bithenge_transform_dec_ref(self->true_xform);
215 bithenge_transform_dec_ref(self->false_xform);
216 free(self);
217}
218
219static const bithenge_transform_ops_t if_transform_ops = {
220 .apply = if_transform_apply,
221 .prefix_length = if_transform_prefix_length,
222 .destroy = if_transform_destroy,
223};
224
225/** Create a transform that applies either of two transforms depending on a
226 * boolean expression. Takes references to @a expr, @a true_xform, and
227 * @a false_xform.
228 * @param[out] out Holds the new transform.
229 * @param expr The boolean expression to evaluate.
230 * @param true_xform The transform to apply if the expression is true.
231 * @param false_xform The transform to apply if the expression is false.
232 * @return EOK on success or an error code from errno.h. */
233int bithenge_if_transform(bithenge_transform_t **out,
234 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
235 bithenge_transform_t *false_xform)
236{
237 int rc;
238 if_transform_t *self = malloc(sizeof(*self));
239 if (!self) {
240 rc = ENOMEM;
241 goto error;
242 }
243
244 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
245 0);
246 if (rc != EOK)
247 goto error;
248
249 self->expr = expr;
250 self->true_xform = true_xform;
251 self->false_xform = false_xform;
252 *out = if_as_transform(self);
253 return EOK;
254
255error:
256 free(self);
257 bithenge_expression_dec_ref(expr);
258 bithenge_transform_dec_ref(true_xform);
259 bithenge_transform_dec_ref(false_xform);
260 return rc;
261}
262
263
264
265/***************** partial_transform *****************/
266
267typedef struct {
268 bithenge_transform_t base;
269 bithenge_transform_t *xform;
270} partial_transform_t;
271
272static inline bithenge_transform_t *partial_as_transform(
273 partial_transform_t *self)
274{
275 return &self->base;
276}
277
278static inline partial_transform_t *transform_as_partial(
279 bithenge_transform_t *base)
280{
281 return (partial_transform_t *)base;
282}
283
284static int partial_transform_apply(bithenge_transform_t *base,
285 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
286{
287 partial_transform_t *self = transform_as_partial(base);
288 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
289 return EINVAL;
290 return bithenge_transform_prefix_apply(self->xform, scope,
291 bithenge_node_as_blob(in), out, NULL);
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.