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

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

Fix spacing in single-line comments using latest ccheck

This found incorrectly formatted section comments (with blocks of
asterisks or dashes). I strongly believe against using section comments
but I am not simply removing them since that would probably be
controversial.

  • 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 <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 * compose_transform
46 */
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.
118 */
119errno_t bithenge_new_composed_transform(bithenge_transform_t **out,
120 bithenge_transform_t **xforms, size_t num)
121{
122 if (num == 0) {
123 /* TODO: optimize */
124 } else if (num == 1) {
125 *out = xforms[0];
126 free(xforms);
127 return EOK;
128 }
129
130 errno_t rc;
131 compose_transform_t *self = malloc(sizeof(*self));
132 if (!self) {
133 rc = ENOMEM;
134 goto error;
135 }
136 rc = bithenge_init_transform(compose_as_transform(self),
137 &compose_transform_ops, 0);
138 if (rc != EOK)
139 goto error;
140 self->xforms = xforms;
141 self->num = num;
142 *out = compose_as_transform(self);
143 return EOK;
144error:
145 for (size_t i = 0; i < num; i++)
146 bithenge_transform_dec_ref(xforms[i]);
147 free(xforms);
148 free(self);
149 return rc;
150}
151
152/*
153 * if_transform
154 */
155
156typedef struct {
157 bithenge_transform_t base;
158 bithenge_expression_t *expr;
159 bithenge_transform_t *true_xform, *false_xform;
160} if_transform_t;
161
162static inline bithenge_transform_t *if_as_transform(if_transform_t *self)
163{
164 return &self->base;
165}
166
167static inline if_transform_t *transform_as_if(bithenge_transform_t *base)
168{
169 return (if_transform_t *)base;
170}
171
172static errno_t if_transform_choose(if_transform_t *self, bithenge_scope_t *scope,
173 bool *out)
174{
175 bithenge_node_t *cond_node;
176 errno_t rc = bithenge_expression_evaluate(self->expr, scope, &cond_node);
177 if (rc != EOK)
178 return rc;
179 if (bithenge_node_type(cond_node) != BITHENGE_NODE_BOOLEAN) {
180 bithenge_node_dec_ref(cond_node);
181 return EINVAL;
182 }
183 *out = bithenge_boolean_node_value(cond_node);
184 bithenge_node_dec_ref(cond_node);
185 return EOK;
186}
187
188static errno_t if_transform_apply(bithenge_transform_t *base,
189 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
190{
191 if_transform_t *self = transform_as_if(base);
192 bool cond;
193 errno_t rc = if_transform_choose(self, scope, &cond);
194 if (rc != EOK)
195 return rc;
196 return bithenge_transform_apply(
197 cond ? self->true_xform : self->false_xform, scope, in, out);
198}
199
200static errno_t if_transform_prefix_length(bithenge_transform_t *base,
201 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
202{
203 if_transform_t *self = transform_as_if(base);
204 bool cond;
205 errno_t rc = if_transform_choose(self, scope, &cond);
206 if (rc != EOK)
207 return rc;
208 return bithenge_transform_prefix_length(
209 cond ? self->true_xform : self->false_xform, scope, in, out);
210}
211
212static void if_transform_destroy(bithenge_transform_t *base)
213{
214 if_transform_t *self = transform_as_if(base);
215 bithenge_expression_dec_ref(self->expr);
216 bithenge_transform_dec_ref(self->true_xform);
217 bithenge_transform_dec_ref(self->false_xform);
218 free(self);
219}
220
221static const bithenge_transform_ops_t if_transform_ops = {
222 .apply = if_transform_apply,
223 .prefix_length = if_transform_prefix_length,
224 .destroy = if_transform_destroy,
225};
226
227/** Create a transform that applies either of two transforms depending on a
228 * boolean expression. Takes references to @a expr, @a true_xform, and
229 * @a false_xform.
230 * @param[out] out Holds the new transform.
231 * @param expr The boolean expression to evaluate.
232 * @param true_xform The transform to apply if the expression is true.
233 * @param false_xform The transform to apply if the expression is false.
234 * @return EOK on success or an error code from errno.h.
235 */
236errno_t bithenge_if_transform(bithenge_transform_t **out,
237 bithenge_expression_t *expr, bithenge_transform_t *true_xform,
238 bithenge_transform_t *false_xform)
239{
240 errno_t rc;
241 if_transform_t *self = malloc(sizeof(*self));
242 if (!self) {
243 rc = ENOMEM;
244 goto error;
245 }
246
247 rc = bithenge_init_transform(if_as_transform(self), &if_transform_ops,
248 0);
249 if (rc != EOK)
250 goto error;
251
252 self->expr = expr;
253 self->true_xform = true_xform;
254 self->false_xform = false_xform;
255 *out = if_as_transform(self);
256 return EOK;
257
258error:
259 free(self);
260 bithenge_expression_dec_ref(expr);
261 bithenge_transform_dec_ref(true_xform);
262 bithenge_transform_dec_ref(false_xform);
263 return rc;
264}
265
266/*
267 * partial_transform
268 */
269
270typedef struct {
271 bithenge_transform_t base;
272 bithenge_transform_t *xform;
273} partial_transform_t;
274
275static inline bithenge_transform_t *partial_as_transform(
276 partial_transform_t *self)
277{
278 return &self->base;
279}
280
281static inline partial_transform_t *transform_as_partial(
282 bithenge_transform_t *base)
283{
284 return (partial_transform_t *)base;
285}
286
287static errno_t partial_transform_apply(bithenge_transform_t *base,
288 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
289{
290 partial_transform_t *self = transform_as_partial(base);
291 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
292 return EINVAL;
293 return bithenge_transform_prefix_apply(self->xform, scope,
294 bithenge_node_as_blob(in), out, NULL);
295}
296
297static void partial_transform_destroy(bithenge_transform_t *base)
298{
299 partial_transform_t *self = transform_as_partial(base);
300 bithenge_transform_dec_ref(self->xform);
301 free(self);
302}
303
304static const bithenge_transform_ops_t partial_transform_ops = {
305 .apply = partial_transform_apply,
306 .destroy = partial_transform_destroy,
307};
308
309/** Create a transform that doesn't require its subtransform to use the whole
310 * input. Takes a reference to @a xform.
311 * @param[out] out Holds the new transform.
312 * @param xform The subtransform to apply.
313 * @return EOK on success or an error code from errno.h.
314 */
315errno_t bithenge_partial_transform(bithenge_transform_t **out,
316 bithenge_transform_t *xform)
317{
318 errno_t rc;
319 partial_transform_t *self = malloc(sizeof(*self));
320 if (!self) {
321 rc = ENOMEM;
322 goto error;
323 }
324
325 rc = bithenge_init_transform(partial_as_transform(self),
326 &partial_transform_ops, 0);
327 if (rc != EOK)
328 goto error;
329
330 self->xform = xform;
331 *out = partial_as_transform(self);
332 return EOK;
333
334error:
335 free(self);
336 bithenge_transform_dec_ref(xform);
337 return rc;
338}
339
340/** @}
341 */
Note: See TracBrowser for help on using the repository browser.