Use `errno_t` in all uspace and kernel code.
[helenos.git] / uspace / lib / bithenge / src / compound.c
blobec0e8e581ba44d339b860b84219f0f3ebf6ccccc
1 /*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
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.
29 /** @addtogroup bithenge
30 * @{
32 /**
33 * @file
34 * Compound transforms.
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"
46 /***************** compose_transform *****************/
48 typedef struct {
49 bithenge_transform_t base;
50 bithenge_transform_t **xforms;
51 size_t num;
52 } compose_transform_t;
54 static bithenge_transform_t *compose_as_transform(compose_transform_t *xform)
56 return &xform->base;
59 static compose_transform_t *transform_as_compose(bithenge_transform_t *xform)
61 return (compose_transform_t *)xform;
64 static errno_t compose_apply(bithenge_transform_t *base, bithenge_scope_t *scope,
65 bithenge_node_t *in, bithenge_node_t **out)
67 errno_t rc;
68 compose_transform_t *self = transform_as_compose(base);
69 bithenge_node_inc_ref(in);
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;
82 *out = in;
83 return EOK;
86 static errno_t compose_prefix_length(bithenge_transform_t *base,
87 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
89 compose_transform_t *self = transform_as_compose(base);
90 return bithenge_transform_prefix_length(self->xforms[self->num - 1],
91 scope, blob, out);
94 static void compose_destroy(bithenge_transform_t *base)
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);
103 static const bithenge_transform_ops_t compose_transform_ops = {
104 .apply = compose_apply,
105 .prefix_length = compose_prefix_length,
106 .destroy = compose_destroy,
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. */
117 errno_t bithenge_new_composed_transform(bithenge_transform_t **out,
118 bithenge_transform_t **xforms, size_t num)
120 if (num == 0) {
121 /* TODO: optimize */
122 } else if (num == 1) {
123 *out = xforms[0];
124 free(xforms);
125 return EOK;
128 errno_t rc;
129 compose_transform_t *self = malloc(sizeof(*self));
130 if (!self) {
131 rc = ENOMEM;
132 goto error;
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;
142 error:
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;
152 /***************** if_transform *****************/
154 typedef struct {
155 bithenge_transform_t base;
156 bithenge_expression_t *expr;
157 bithenge_transform_t *true_xform, *false_xform;
158 } if_transform_t;
160 static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
162 return &self->base;
165 static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
167 return (if_transform_t *)base;
170 static errno_t if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
171 bool *out)
173 bithenge_node_t *cond_node;
174 errno_t 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;
181 *out = bithenge_boolean_node_value(cond_node);
182 bithenge_node_dec_ref(cond_node);
183 return EOK;
186 static errno_t if_transform_apply(bithenge_transform_t *base,
187 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
189 if_transform_t *self = transform_as_if(base);
190 bool cond;
191 errno_t 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);
198 static errno_t if_transform_prefix_length(bithenge_transform_t *base,
199 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
201 if_transform_t *self = transform_as_if(base);
202 bool cond;
203 errno_t 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);
210 static void if_transform_destroy(bithenge_transform_t *base)
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);
219 static 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,
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. */
233 errno_t bithenge_if_transform(bithenge_transform_t **out,
234 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
235 bithenge_transform_t *false_xform)
237 errno_t rc;
238 if_transform_t *self = malloc(sizeof(*self));
239 if (!self) {
240 rc = ENOMEM;
241 goto error;
244 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
246 if (rc != EOK)
247 goto error;
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;
255 error:
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;
265 /***************** partial_transform *****************/
267 typedef struct {
268 bithenge_transform_t base;
269 bithenge_transform_t *xform;
270 } partial_transform_t;
272 static inline bithenge_transform_t *partial_as_transform(
273 partial_transform_t *self)
275 return &self->base;
278 static inline partial_transform_t *transform_as_partial(
279 bithenge_transform_t *base)
281 return (partial_transform_t *)base;
284 static errno_t partial_transform_apply(bithenge_transform_t *base,
285 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
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);
294 static void partial_transform_destroy(bithenge_transform_t *base)
296 partial_transform_t *self = transform_as_partial(base);
297 bithenge_transform_dec_ref(self->xform);
298 free(self);
301 static const bithenge_transform_ops_t partial_transform_ops = {
302 .apply = partial_transform_apply,
303 .destroy = partial_transform_destroy,
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. */
311 errno_t bithenge_partial_transform(bithenge_transform_t **out,
312 bithenge_transform_t *xform)
314 errno_t rc;
315 partial_transform_t *self = malloc(sizeof(*self));
316 if (!self) {
317 rc = ENOMEM;
318 goto error;
321 rc = bithenge_init_transform(partial_as_transform(self),
322 &partial_transform_ops, 0);
323 if (rc != EOK)
324 goto error;
326 self->xform = xform;
327 *out = partial_as_transform(self);
328 return EOK;
330 error:
331 free(self);
332 bithenge_transform_dec_ref(xform);
333 return rc;
336 /** @}