source: mainline/uspace/lib/bithenge/src/sequence.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: 29.1 KB
RevLine 
[0f8062a4]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 * Sequence transforms.
35 */
36
37#include <stdlib.h>
[8fc0f47c]38#include <bithenge/blob.h>
39#include <bithenge/expression.h>
40#include <bithenge/os.h>
41#include <bithenge/sequence.h>
42#include <bithenge/tree.h>
[0f8062a4]43
44
45
[c3437d9]46/***************** seq_node *****************/
47
[0f8062a4]48typedef struct {
49 bithenge_node_t base;
50 const struct seq_node_ops *ops;
51 bithenge_blob_t *blob;
[f9c314a5]52 bithenge_scope_t *scope;
[0f8062a4]53 aoff64_t *ends;
54 size_t num_ends;
[e3f2765]55 bool end_on_empty;
[0f8062a4]56 bithenge_int_t num_xforms;
57} seq_node_t;
58
59typedef struct seq_node_ops {
60 int (*get_transform)(seq_node_t *self, bithenge_transform_t **out,
61 bithenge_int_t index);
62} seq_node_ops_t;
63
64static bithenge_node_t *seq_as_node(seq_node_t *node)
65{
66 return &node->base;
67}
68
69static seq_node_t *node_as_seq(bithenge_node_t *node)
70{
71 return (seq_node_t *)node;
72}
73
74static int seq_node_field_offset(seq_node_t *self, aoff64_t *out, size_t index)
75{
76 if (index == 0) {
77 *out = 0;
78 return EOK;
79 }
80 index--;
81 aoff64_t prev_offset =
82 self->num_ends ? self->ends[self->num_ends - 1] : 0;
83 for (; self->num_ends <= index; self->num_ends++) {
84 bithenge_transform_t *subxform;
85 int rc = self->ops->get_transform(self, &subxform,
86 self->num_ends);
87 if (rc != EOK)
88 return rc;
89
90 bithenge_node_t *subblob_node;
91 bithenge_blob_inc_ref(self->blob);
92 rc = bithenge_new_offset_blob(&subblob_node, self->blob,
93 prev_offset);
94 if (rc != EOK) {
95 bithenge_transform_dec_ref(subxform);
96 return rc;
97 }
98
[e3f2765]99 if (self->end_on_empty) {
100 bool empty;
101 rc = bithenge_blob_empty(
102 bithenge_node_as_blob(subblob_node), &empty);
103 if (rc == EOK && empty) {
104 self->num_xforms = self->num_ends;
105 rc = ENOENT;
106 }
107 if (rc != EOK) {
108 bithenge_transform_dec_ref(subxform);
109 bithenge_node_dec_ref(subblob_node);
110 return rc;
111 }
112 }
113
[0f8062a4]114 bithenge_blob_t *subblob = bithenge_node_as_blob(subblob_node);
115 aoff64_t field_size;
[f9c314a5]116 rc = bithenge_transform_prefix_length(subxform, self->scope,
[0f8062a4]117 subblob, &field_size);
118 bithenge_node_dec_ref(subblob_node);
119 bithenge_transform_dec_ref(subxform);
120 if (rc != EOK)
121 return rc;
122
[e3f2765]123 if (self->num_xforms == -1) {
124 aoff64_t *new_ends = realloc(self->ends,
125 (self->num_ends + 1)*sizeof(*new_ends));
126 if (!new_ends)
127 return ENOMEM;
128 self->ends = new_ends;
129 }
130
[0f8062a4]131 prev_offset = self->ends[self->num_ends] =
132 prev_offset + field_size;
133 }
134 *out = self->ends[index];
135 return EOK;
136}
137
138static int seq_node_subtransform(seq_node_t *self, bithenge_node_t **out,
139 size_t index)
140{
141 aoff64_t start_pos;
142 int rc = seq_node_field_offset(self, &start_pos, index);
143 if (rc != EOK)
144 return rc;
145
146 bithenge_transform_t *subxform;
147 rc = self->ops->get_transform(self, &subxform, index);
148 if (rc != EOK)
149 return rc;
150
151 if (index == self->num_ends) {
152 /* We can apply the subtransform and cache its prefix length at
153 * the same time. */
154 bithenge_node_t *blob_node;
155 bithenge_blob_inc_ref(self->blob);
156 rc = bithenge_new_offset_blob(&blob_node, self->blob,
157 start_pos);
158 if (rc != EOK) {
159 bithenge_transform_dec_ref(subxform);
160 return rc;
161 }
162
[e3f2765]163 if (self->end_on_empty) {
164 bool empty;
165 rc = bithenge_blob_empty(
166 bithenge_node_as_blob(blob_node), &empty);
167 if (rc == EOK && empty) {
168 self->num_xforms = self->num_ends;
169 rc = ENOENT;
170 }
171 if (rc != EOK) {
172 bithenge_transform_dec_ref(subxform);
173 bithenge_node_dec_ref(blob_node);
174 return rc;
175 }
176 }
177
[0f8062a4]178 aoff64_t size;
[f9c314a5]179 rc = bithenge_transform_prefix_apply(subxform, self->scope,
[0f8062a4]180 bithenge_node_as_blob(blob_node), out, &size);
181 bithenge_node_dec_ref(blob_node);
182 bithenge_transform_dec_ref(subxform);
183 if (rc != EOK)
184 return rc;
185
[e3f2765]186 if (self->num_xforms == -1) {
187 aoff64_t *new_ends = realloc(self->ends,
188 (self->num_ends + 1)*sizeof(*new_ends));
189 if (!new_ends)
190 return ENOMEM;
191 self->ends = new_ends;
192 }
[0f8062a4]193 self->ends[self->num_ends++] = start_pos + size;
194 } else {
195 aoff64_t end_pos;
196 int rc = seq_node_field_offset(self, &end_pos, index + 1);
197 if (rc != EOK) {
198 bithenge_transform_dec_ref(subxform);
199 return rc;
200 }
201
202 bithenge_node_t *blob_node;
203 bithenge_blob_inc_ref(self->blob);
204 rc = bithenge_new_subblob(&blob_node, self->blob, start_pos,
205 end_pos - start_pos);
206 if (rc != EOK) {
207 bithenge_transform_dec_ref(subxform);
208 return rc;
209 }
210
[f9c314a5]211 rc = bithenge_transform_apply(subxform, self->scope, blob_node,
212 out);
[0f8062a4]213 bithenge_node_dec_ref(blob_node);
214 bithenge_transform_dec_ref(subxform);
215 if (rc != EOK)
216 return rc;
217 }
218
219 return EOK;
220}
221
222static int seq_node_complete(seq_node_t *self, bool *out)
223{
224 aoff64_t blob_size, end_pos;
225 int rc = bithenge_blob_size(self->blob, &blob_size);
226 if (rc != EOK)
227 return rc;
228 rc = seq_node_field_offset(self, &end_pos, self->num_xforms);
229 if (rc != EOK)
230 return rc;
231 *out = blob_size == end_pos;
232 return EOK;
233}
234
235static void seq_node_destroy(seq_node_t *self)
236{
[f9c314a5]237 bithenge_scope_dec_ref(self->scope);
[0f8062a4]238 bithenge_blob_dec_ref(self->blob);
239 free(self->ends);
240}
241
[c3437d9]242static void seq_node_set_num_xforms(seq_node_t *self,
243 bithenge_int_t num_xforms)
244{
245 self->num_xforms = num_xforms;
246}
247
[0f8062a4]248static bithenge_scope_t *seq_node_scope(seq_node_t *self)
249{
[f9c314a5]250 return self->scope;
[0f8062a4]251}
252
253static int seq_node_init(seq_node_t *self, const seq_node_ops_t *ops,
[e3f2765]254 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_int_t num_xforms,
255 bool end_on_empty)
[0f8062a4]256{
257 self->ops = ops;
[e3f2765]258 if (num_xforms != -1) {
259 self->ends = malloc(sizeof(*self->ends) * num_xforms);
260 if (!self->ends)
261 return ENOMEM;
262 } else
263 self->ends = NULL;
[0f8062a4]264 bithenge_blob_inc_ref(blob);
265 self->blob = blob;
266 self->num_xforms = num_xforms;
267 self->num_ends = 0;
[e3f2765]268 self->end_on_empty = end_on_empty;
[0191bd3]269 self->scope = scope;
270 if (self->scope)
271 bithenge_scope_inc_ref(self->scope);
[0f8062a4]272 return EOK;
273}
274
275
276
[c3437d9]277/***************** bithenge_new_struct *****************/
278
[0f8062a4]279typedef struct {
280 bithenge_transform_t base;
281 bithenge_named_transform_t *subtransforms;
282 size_t num_subtransforms;
283} struct_transform_t;
284
285static bithenge_transform_t *struct_as_transform(struct_transform_t *xform)
286{
287 return &xform->base;
288}
289
290static struct_transform_t *transform_as_struct(bithenge_transform_t *xform)
291{
292 return (struct_transform_t *)xform;
293}
294
295typedef struct {
296 seq_node_t base;
297 struct_transform_t *transform;
298 bool prefix;
299} struct_node_t;
300
301static seq_node_t *struct_as_seq(struct_node_t *node)
302{
303 return &node->base;
304}
305
306static struct_node_t *seq_as_struct(seq_node_t *base)
307{
308 return (struct_node_t *)base;
309}
310
311static bithenge_node_t *struct_as_node(struct_node_t *node)
312{
313 return seq_as_node(struct_as_seq(node));
314}
315
316static struct_node_t *node_as_struct(bithenge_node_t *node)
317{
318 return seq_as_struct(node_as_seq(node));
319}
320
321static int struct_node_for_each(bithenge_node_t *base,
322 bithenge_for_each_func_t func, void *data)
323{
324 int rc = EOK;
325 struct_node_t *self = node_as_struct(base);
326 bithenge_named_transform_t *subxforms =
327 self->transform->subtransforms;
328
329 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
330 bithenge_node_t *subxform_result;
331 rc = seq_node_subtransform(struct_as_seq(self),
332 &subxform_result, i);
333 if (rc != EOK)
334 return rc;
335
336 if (subxforms[i].name) {
337 bithenge_node_t *name_node;
338 rc = bithenge_new_string_node(&name_node,
339 subxforms[i].name, false);
340 if (rc == EOK) {
341 rc = func(name_node, subxform_result, data);
342 subxform_result = NULL;
343 }
344 } else {
345 if (bithenge_node_type(subxform_result) !=
346 BITHENGE_NODE_INTERNAL) {
347 rc = EINVAL;
348 } else {
349 rc = bithenge_node_for_each(subxform_result,
350 func, data);
351 }
352 }
353 bithenge_node_dec_ref(subxform_result);
354 if (rc != EOK)
355 return rc;
356 }
357
358 if (!self->prefix) {
359 bool complete;
360 rc = seq_node_complete(struct_as_seq(self), &complete);
361 if (rc != EOK)
362 return rc;
363 if (!complete)
364 return EINVAL;
365 }
366
367 return rc;
368}
369
370static int struct_node_get(bithenge_node_t *base, bithenge_node_t *key,
371 bithenge_node_t **out)
372{
373 struct_node_t *self = node_as_struct(base);
374
375 int rc = ENOENT;
376 if (bithenge_node_type(key) != BITHENGE_NODE_STRING)
377 goto end;
378 const char *name = bithenge_string_node_value(key);
379
380 const bithenge_named_transform_t *subxforms =
381 self->transform->subtransforms;
382 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
383 if (subxforms[i].name && !str_cmp(name, subxforms[i].name)) {
384 rc = seq_node_subtransform(struct_as_seq(self), out, i);
385 goto end;
386 }
387 }
388
389 for (bithenge_int_t i = 0; subxforms[i].transform; i++) {
390 if (subxforms[i].name)
391 continue;
392 bithenge_node_t *subxform_result;
393 rc = seq_node_subtransform(struct_as_seq(self),
394 &subxform_result, i);
395 if (rc != EOK)
396 goto end;
397 if (bithenge_node_type(subxform_result) !=
398 BITHENGE_NODE_INTERNAL) {
399 bithenge_node_dec_ref(subxform_result);
400 rc = EINVAL;
401 goto end;
402 }
403 bithenge_node_inc_ref(key);
404 rc = bithenge_node_get(subxform_result, key, out);
405 bithenge_node_dec_ref(subxform_result);
406 if (rc != ENOENT)
407 goto end;
408 }
409
410 rc = ENOENT;
411end:
412 bithenge_node_dec_ref(key);
413 return rc;
414}
415
416static void struct_node_destroy(bithenge_node_t *base)
417{
418 struct_node_t *node = node_as_struct(base);
419
[6be4142]420 /* Treat the scope carefully because of the circular reference. In
421 * struct_transform_make_node, things are set up so node owns a
422 * reference to the scope, but scope doesn't own a reference to node,
423 * so node's reference count is too low. */
424 bithenge_scope_t *scope = seq_node_scope(struct_as_seq(node));
425 if (scope->refs == 1) {
426 /* Mostly normal destroy, but we didn't inc_ref(node) for the
427 * scope in struct_transform_make_node, so make sure it doesn't
428 * try to dec_ref. */
429 scope->current_node = NULL;
430 seq_node_destroy(struct_as_seq(node));
431 } else if (scope->refs > 1) {
432 /* The scope is still needed, but node isn't otherwise needed.
433 * Switch things around so scope owns a reference to node, but
434 * not vice versa, and scope's reference count is too low. */
435 bithenge_node_inc_ref(base);
436 bithenge_scope_dec_ref(scope);
437 return;
438 } else {
439 /* This happens after the previous case, when scope is no
440 * longer used and is being destroyed. Since scope is already
441 * being destroyed, set it to NULL here so we don't try to
442 * destroy it twice. */
443 struct_as_seq(node)->scope = NULL;
444 seq_node_destroy(struct_as_seq(node));
445 }
[0f8062a4]446
447 bithenge_transform_dec_ref(struct_as_transform(node->transform));
448 free(node);
449}
450
451static const bithenge_internal_node_ops_t struct_node_ops = {
452 .for_each = struct_node_for_each,
453 .get = struct_node_get,
454 .destroy = struct_node_destroy,
455};
456
457static int struct_node_get_transform(seq_node_t *base,
458 bithenge_transform_t **out, bithenge_int_t index)
459{
460 struct_node_t *self = seq_as_struct(base);
461 *out = self->transform->subtransforms[index].transform;
462 bithenge_transform_inc_ref(*out);
463 return EOK;
464}
465
466static const seq_node_ops_t struct_node_seq_ops = {
467 .get_transform = struct_node_get_transform,
468};
469
470static int struct_transform_make_node(struct_transform_t *self,
471 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
472 bool prefix)
473{
474 struct_node_t *node = malloc(sizeof(*node));
475 if (!node)
476 return ENOMEM;
477
478 int rc = bithenge_init_internal_node(struct_as_node(node),
479 &struct_node_ops);
480 if (rc != EOK) {
481 free(node);
482 return rc;
483 }
[0191bd3]484 bithenge_scope_t *inner;
485 rc = bithenge_scope_new(&inner, scope);
486 if (rc != EOK) {
487 free(node);
488 return rc;
489 }
[0f8062a4]490
[0191bd3]491 rc = seq_node_init(struct_as_seq(node), &struct_node_seq_ops, inner,
[e3f2765]492 blob, self->num_subtransforms, false);
[0f8062a4]493 if (rc != EOK) {
[a42d7d8]494 bithenge_scope_dec_ref(inner);
[0f8062a4]495 free(node);
496 return rc;
497 }
498
499 bithenge_transform_inc_ref(struct_as_transform(self));
500 node->transform = self;
501 node->prefix = prefix;
[a42d7d8]502
503 /* We should inc_ref(node) here, but that would make a cycle. Instead,
504 * we leave it 1 too low, so that when the only remaining use of node
505 * is the scope, node will be destroyed. Also see the comment in
506 * struct_node_destroy. */
507 bithenge_scope_set_current_node(inner, struct_as_node(node));
508 bithenge_scope_dec_ref(inner);
509
[0f8062a4]510 *out = struct_as_node(node);
511
512 return EOK;
513}
514
515static int struct_transform_apply(bithenge_transform_t *base,
516 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
517{
518 struct_transform_t *self = transform_as_struct(base);
519 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
520 return EINVAL;
521 return struct_transform_make_node(self, out, scope,
522 bithenge_node_as_blob(in), false);
523}
524
525static int struct_transform_prefix_length(bithenge_transform_t *base,
526 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
527{
528 struct_transform_t *self = transform_as_struct(base);
529 bithenge_node_t *struct_node;
530 int rc = struct_transform_make_node(self, &struct_node, scope, blob,
531 true);
532 if (rc != EOK)
533 return rc;
534
535 rc = seq_node_field_offset(node_as_seq(struct_node), out,
536 self->num_subtransforms);
537 bithenge_node_dec_ref(struct_node);
538 return rc;
539}
540
541static int struct_transform_prefix_apply(bithenge_transform_t *base,
542 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
543 aoff64_t *out_size)
544{
545 struct_transform_t *self = transform_as_struct(base);
546 int rc = struct_transform_make_node(self, out_node, scope, blob,
547 true);
548 if (rc != EOK)
549 return rc;
550
[1b6b76d]551 if (out_size) {
552 rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
553 self->num_subtransforms);
554 if (rc != EOK) {
555 bithenge_node_dec_ref(*out_node);
556 return rc;
557 }
[0f8062a4]558 }
559
560 return EOK;
561}
562
563static void free_subtransforms(bithenge_named_transform_t *subtransforms)
564{
565 for (size_t i = 0; subtransforms[i].transform; i++) {
566 free((void *)subtransforms[i].name);
567 bithenge_transform_dec_ref(subtransforms[i].transform);
568 }
569 free(subtransforms);
570}
571
572static void struct_transform_destroy(bithenge_transform_t *base)
573{
574 struct_transform_t *self = transform_as_struct(base);
575 free_subtransforms(self->subtransforms);
576 free(self);
577}
578
579static bithenge_transform_ops_t struct_transform_ops = {
580 .apply = struct_transform_apply,
581 .prefix_length = struct_transform_prefix_length,
582 .prefix_apply = struct_transform_prefix_apply,
583 .destroy = struct_transform_destroy,
584};
585
586/** Create a struct transform. The transform will apply its subtransforms
587 * sequentially to a blob to create an internal node. Each result is either
588 * given a key from @a subtransforms or, if the name is NULL, the result's keys
589 * and values are merged into the struct transform's result. This function
590 * takes ownership of @a subtransforms and the names and references therein.
591 * @param[out] out Stores the created transform.
592 * @param subtransforms The subtransforms and field names.
593 * @return EOK on success or an error code from errno.h. */
594int bithenge_new_struct(bithenge_transform_t **out,
595 bithenge_named_transform_t *subtransforms)
596{
597 int rc;
598 struct_transform_t *self = malloc(sizeof(*self));
599 if (!self) {
600 rc = ENOMEM;
601 goto error;
602 }
603 rc = bithenge_init_transform(struct_as_transform(self),
604 &struct_transform_ops, 0);
605 if (rc != EOK)
606 goto error;
607 self->subtransforms = subtransforms;
608 self->num_subtransforms = 0;
609 for (self->num_subtransforms = 0;
610 subtransforms[self->num_subtransforms].transform;
611 self->num_subtransforms++);
612 *out = struct_as_transform(self);
613 return EOK;
614error:
615 free_subtransforms(subtransforms);
616 free(self);
617 return rc;
618}
619
[ee7cc3c]620
621
[c3437d9]622/***************** bithenge_repeat_transform *****************/
623
[2988aec7]624/* TODO: ignore errors */
625
[ee7cc3c]626typedef struct {
627 bithenge_transform_t base;
628 bithenge_expression_t *expr;
629 bithenge_transform_t *xform;
630} repeat_transform_t;
631
632static inline bithenge_transform_t *repeat_as_transform(
633 repeat_transform_t *self)
634{
635 return &self->base;
636}
637
638static inline repeat_transform_t *transform_as_repeat(
639 bithenge_transform_t *base)
640{
641 return (repeat_transform_t *)base;
642}
643
644typedef struct {
645 seq_node_t base;
646 bool prefix;
647 bithenge_int_t count;
648 bithenge_transform_t *xform;
649} repeat_node_t;
650
651static seq_node_t *repeat_as_seq(repeat_node_t *self)
652{
653 return &self->base;
654}
655
656static repeat_node_t *seq_as_repeat(seq_node_t *base)
657{
658 return (repeat_node_t *)base;
659}
660
661static bithenge_node_t *repeat_as_node(repeat_node_t *self)
662{
663 return seq_as_node(repeat_as_seq(self));
664}
665
666static repeat_node_t *node_as_repeat(bithenge_node_t *base)
667{
668 return seq_as_repeat(node_as_seq(base));
669}
670
671static int repeat_node_for_each(bithenge_node_t *base,
672 bithenge_for_each_func_t func, void *data)
673{
674 int rc = EOK;
675 repeat_node_t *self = node_as_repeat(base);
676
[e3f2765]677 for (bithenge_int_t i = 0; self->count == -1 || i < self->count; i++) {
[ee7cc3c]678 bithenge_node_t *subxform_result;
679 rc = seq_node_subtransform(repeat_as_seq(self),
680 &subxform_result, i);
[c3437d9]681 if ((rc == EINVAL || rc == ENOENT) && self->count == -1) {
682 self->count = i;
683 seq_node_set_num_xforms(repeat_as_seq(self),
684 self->count);
[e3f2765]685 rc = EOK;
686 break;
687 }
[ee7cc3c]688 if (rc != EOK)
689 return rc;
690
691 bithenge_node_t *key_node;
692 rc = bithenge_new_integer_node(&key_node, i);
693 if (rc != EOK) {
694 bithenge_node_dec_ref(subxform_result);
695 return rc;
696 }
697 rc = func(key_node, subxform_result, data);
698 if (rc != EOK)
699 return rc;
700 }
701
702 if (!self->prefix) {
703 bool complete;
704 rc = seq_node_complete(repeat_as_seq(self), &complete);
705 if (rc != EOK)
706 return rc;
707 if (!complete)
708 return EINVAL;
709 }
710
711 return rc;
712}
713
714static int repeat_node_get(bithenge_node_t *base, bithenge_node_t *key,
715 bithenge_node_t **out)
716{
717 repeat_node_t *self = node_as_repeat(base);
718
719 if (bithenge_node_type(key) != BITHENGE_NODE_INTEGER) {
720 bithenge_node_dec_ref(key);
721 return ENOENT;
722 }
723
724 bithenge_int_t index = bithenge_integer_node_value(key);
725 bithenge_node_dec_ref(key);
[e3f2765]726 if (index < 0 || (self->count != -1 && index >= self->count))
[ee7cc3c]727 return ENOENT;
728 return seq_node_subtransform(repeat_as_seq(self), out, index);
729}
730
731static void repeat_node_destroy(bithenge_node_t *base)
732{
733 repeat_node_t *self = node_as_repeat(base);
734 seq_node_destroy(repeat_as_seq(self));
735 bithenge_transform_dec_ref(self->xform);
736 free(self);
737}
738
739static const bithenge_internal_node_ops_t repeat_node_ops = {
740 .for_each = repeat_node_for_each,
741 .get = repeat_node_get,
742 .destroy = repeat_node_destroy,
743};
744
745static int repeat_node_get_transform(seq_node_t *base,
746 bithenge_transform_t **out, bithenge_int_t index)
747{
748 repeat_node_t *self = seq_as_repeat(base);
749 *out = self->xform;
750 bithenge_transform_inc_ref(*out);
751 return EOK;
752}
753
754static const seq_node_ops_t repeat_node_seq_ops = {
755 .get_transform = repeat_node_get_transform,
756};
757
758static int repeat_transform_make_node(repeat_transform_t *self,
759 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
760 bool prefix)
761{
[e3f2765]762 bithenge_int_t count = -1;
763 if (self->expr != NULL) {
764 bithenge_node_t *count_node;
765 int rc = bithenge_expression_evaluate(self->expr, scope,
766 &count_node);
767 if (rc != EOK)
768 return rc;
769 if (bithenge_node_type(count_node) != BITHENGE_NODE_INTEGER) {
770 bithenge_node_dec_ref(count_node);
771 return EINVAL;
772 }
773 count = bithenge_integer_node_value(count_node);
[ee7cc3c]774 bithenge_node_dec_ref(count_node);
[e3f2765]775 if (count < 0)
776 return EINVAL;
[ee7cc3c]777 }
778
779 repeat_node_t *node = malloc(sizeof(*node));
780 if (!node)
781 return ENOMEM;
782
[e3f2765]783 int rc = bithenge_init_internal_node(repeat_as_node(node),
[ee7cc3c]784 &repeat_node_ops);
785 if (rc != EOK) {
786 free(node);
787 return rc;
788 }
789
790 rc = seq_node_init(repeat_as_seq(node), &repeat_node_seq_ops, scope,
[e3f2765]791 blob, count, count == -1);
[ee7cc3c]792 if (rc != EOK) {
793 free(node);
794 return rc;
795 }
796
797 bithenge_transform_inc_ref(self->xform);
798 node->xform = self->xform;
799 node->count = count;
[0caaaa00]800 node->prefix = prefix;
[ee7cc3c]801 *out = repeat_as_node(node);
802 return EOK;
803}
804
[e3f2765]805static int repeat_transform_apply(bithenge_transform_t *base,
806 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
807{
808 repeat_transform_t *self = transform_as_repeat(base);
809 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
810 return EINVAL;
811 return repeat_transform_make_node(self, out, scope,
812 bithenge_node_as_blob(in), false);
813}
814
[ee7cc3c]815static int repeat_transform_prefix_apply(bithenge_transform_t *base,
816 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
817 aoff64_t *out_size)
818{
819 repeat_transform_t *self = transform_as_repeat(base);
820 int rc = repeat_transform_make_node(self, out_node, scope, blob, true);
821 if (rc != EOK)
822 return rc;
823
[1b6b76d]824 if (out_size) {
825 bithenge_int_t count = node_as_repeat(*out_node)->count;
826 if (count != -1) {
[e3f2765]827 rc = seq_node_field_offset(node_as_seq(*out_node),
[1b6b76d]828 out_size, count);
829 if (rc != EOK) {
830 bithenge_node_dec_ref(*out_node);
831 return rc;
832 }
833 } else {
834 *out_size = 0;
835 for (count = 1; ; count++) {
836 aoff64_t size;
837 rc = seq_node_field_offset(
838 node_as_seq(*out_node), &size, count);
[a42d7d8]839 if (rc == EINVAL || rc == ENOENT)
[1b6b76d]840 break;
[a42d7d8]841 if (rc != EOK) {
842 bithenge_node_dec_ref(*out_node);
843 return rc;
844 }
[1b6b76d]845 *out_size = size;
846 }
[e3f2765]847 }
[ee7cc3c]848 }
849 return EOK;
850}
851
852static void repeat_transform_destroy(bithenge_transform_t *base)
853{
854 repeat_transform_t *self = transform_as_repeat(base);
855 bithenge_transform_dec_ref(self->xform);
856 bithenge_expression_dec_ref(self->expr);
857 free(self);
858}
859
860static const bithenge_transform_ops_t repeat_transform_ops = {
[e3f2765]861 .apply = repeat_transform_apply,
[ee7cc3c]862 .prefix_apply = repeat_transform_prefix_apply,
863 .destroy = repeat_transform_destroy,
864};
865
866/** Create a transform that applies its subtransform repeatedly. Takes a
867 * reference to @a xform and @a expr.
868 * @param[out] out Holds the new transform.
869 * @param xform The subtransform to apply repeatedly.
870 * @param expr Used to calculate the number of times @a xform will be applied.
871 * May be NULL, in which case @a xform will be applied indefinitely.
872 * @return EOK on success or an error code from errno.h. */
873int bithenge_repeat_transform(bithenge_transform_t **out,
874 bithenge_transform_t *xform, bithenge_expression_t *expr)
875{
876 int rc;
877 repeat_transform_t *self = malloc(sizeof(*self));
878 if (!self) {
879 rc = ENOMEM;
880 goto error;
881 }
882
883 rc = bithenge_init_transform(repeat_as_transform(self),
884 &repeat_transform_ops, 0);
885 if (rc != EOK)
886 goto error;
887
888 self->expr = expr;
889 self->xform = xform;
890 *out = repeat_as_transform(self);
891 return EOK;
892
893error:
894 free(self);
895 bithenge_expression_dec_ref(expr);
896 bithenge_transform_dec_ref(xform);
897 return rc;
898}
899
[c3437d9]900
901
902/***************** bithenge_do_while_transform *****************/
903
904typedef struct {
905 bithenge_transform_t base;
906 bithenge_expression_t *expr;
907 bithenge_transform_t *xform;
908} do_while_transform_t;
909
910static inline bithenge_transform_t *do_while_as_transform(
911 do_while_transform_t *self)
912{
913 return &self->base;
914}
915
916static inline do_while_transform_t *transform_as_do_while(
917 bithenge_transform_t *base)
918{
919 return (do_while_transform_t *)base;
920}
921
922typedef struct {
923 seq_node_t base;
924 bithenge_expression_t *expr;
925 bithenge_transform_t *xform;
926 bithenge_int_t count;
927} do_while_node_t;
928
929static seq_node_t *do_while_as_seq(do_while_node_t *self)
930{
931 return &self->base;
932}
933
934static do_while_node_t *seq_as_do_while(seq_node_t *base)
935{
936 return (do_while_node_t *)base;
937}
938
939static bithenge_node_t *do_while_as_node(do_while_node_t *self)
940{
941 return seq_as_node(do_while_as_seq(self));
942}
943
944static do_while_node_t *node_as_do_while(bithenge_node_t *base)
945{
946 return seq_as_do_while(node_as_seq(base));
947}
948
949static int do_while_node_for_each(bithenge_node_t *base,
950 bithenge_for_each_func_t func, void *data)
951{
952 int rc = EOK;
953 do_while_node_t *self = node_as_do_while(base);
954
955 for (bithenge_int_t i = 0; ; i++) {
956 bithenge_node_t *subxform_result;
957 rc = seq_node_subtransform(do_while_as_seq(self),
958 &subxform_result, i);
959 if (rc != EOK)
960 return rc;
961
962 bithenge_node_t *key_node;
963 rc = bithenge_new_integer_node(&key_node, i);
964 if (rc != EOK) {
965 bithenge_node_dec_ref(subxform_result);
966 return rc;
967 }
968 bithenge_node_inc_ref(subxform_result);
969 rc = func(key_node, subxform_result, data);
970 if (rc != EOK) {
971 bithenge_node_dec_ref(subxform_result);
972 return rc;
973 }
974
[f9c314a5]975 bithenge_scope_t *scope;
[0191bd3]976 rc = bithenge_scope_new(&scope,
977 seq_node_scope(do_while_as_seq(self)));
[f9c314a5]978 if (rc != EOK) {
979 bithenge_node_dec_ref(subxform_result);
980 return rc;
981 }
982 bithenge_scope_set_current_node(scope, subxform_result);
[c3437d9]983 bithenge_node_t *expr_result;
[f9c314a5]984 rc = bithenge_expression_evaluate(self->expr, scope,
[c3437d9]985 &expr_result);
[f9c314a5]986 bithenge_scope_dec_ref(scope);
[c3437d9]987 if (rc != EOK)
988 return rc;
989 if (bithenge_node_type(expr_result) != BITHENGE_NODE_BOOLEAN) {
990 bithenge_node_dec_ref(expr_result);
991 return EINVAL;
992 }
993 bool cond = bithenge_boolean_node_value(expr_result);
994 bithenge_node_dec_ref(expr_result);
995 if (!cond) {
996 self->count = i + 1;
997 seq_node_set_num_xforms(do_while_as_seq(self),
998 self->count);
999 break;
1000 }
1001 }
1002
1003 return rc;
1004}
1005
1006static void do_while_node_destroy(bithenge_node_t *base)
1007{
1008 do_while_node_t *self = node_as_do_while(base);
1009 seq_node_destroy(do_while_as_seq(self));
1010 bithenge_expression_dec_ref(self->expr);
1011 bithenge_transform_dec_ref(self->xform);
1012 free(self);
1013}
1014
1015static const bithenge_internal_node_ops_t do_while_node_ops = {
1016 .for_each = do_while_node_for_each,
1017 .destroy = do_while_node_destroy,
1018};
1019
1020static int do_while_node_get_transform(seq_node_t *base,
1021 bithenge_transform_t **out, bithenge_int_t index)
1022{
1023 do_while_node_t *self = seq_as_do_while(base);
1024 *out = self->xform;
1025 bithenge_transform_inc_ref(*out);
1026 return EOK;
1027}
1028
1029static const seq_node_ops_t do_while_node_seq_ops = {
1030 .get_transform = do_while_node_get_transform,
1031};
1032
1033static int do_while_transform_make_node(do_while_transform_t *self,
[1c79996]1034 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob)
[c3437d9]1035{
1036 do_while_node_t *node = malloc(sizeof(*node));
1037 if (!node)
1038 return ENOMEM;
1039
1040 int rc = bithenge_init_internal_node(do_while_as_node(node),
1041 &do_while_node_ops);
1042 if (rc != EOK) {
1043 free(node);
1044 return rc;
1045 }
1046
1047 rc = seq_node_init(do_while_as_seq(node), &do_while_node_seq_ops,
1048 scope, blob, -1, false);
1049 if (rc != EOK) {
1050 free(node);
1051 return rc;
1052 }
1053
1054 bithenge_transform_inc_ref(self->xform);
1055 node->xform = self->xform;
1056 bithenge_expression_inc_ref(self->expr);
1057 node->expr = self->expr;
1058 node->count = -1;
1059 *out = do_while_as_node(node);
1060 return EOK;
1061}
1062
1063static int for_each_noop(bithenge_node_t *key, bithenge_node_t *value,
1064 void *data)
1065{
1066 bithenge_node_dec_ref(key);
1067 bithenge_node_dec_ref(value);
1068 return EOK;
1069}
1070
1071static int do_while_transform_prefix_apply(bithenge_transform_t *base,
1072 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
1073 aoff64_t *out_size)
1074{
1075 do_while_transform_t *self = transform_as_do_while(base);
[1c79996]1076 int rc = do_while_transform_make_node(self, out_node, scope, blob);
[c3437d9]1077 if (rc != EOK)
1078 return rc;
1079
[1b6b76d]1080 if (out_size) {
1081 rc = bithenge_node_for_each(*out_node, for_each_noop, NULL);
1082 if (rc != EOK) {
1083 bithenge_node_dec_ref(*out_node);
1084 return rc;
1085 }
[c3437d9]1086
[1b6b76d]1087 rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
1088 node_as_do_while(*out_node)->count);
1089 if (rc != EOK) {
1090 bithenge_node_dec_ref(*out_node);
1091 return rc;
1092 }
[c3437d9]1093 }
1094
1095 return EOK;
1096}
1097
1098static void do_while_transform_destroy(bithenge_transform_t *base)
1099{
1100 do_while_transform_t *self = transform_as_do_while(base);
1101 bithenge_transform_dec_ref(self->xform);
1102 bithenge_expression_dec_ref(self->expr);
1103 free(self);
1104}
1105
1106static const bithenge_transform_ops_t do_while_transform_ops = {
1107 .prefix_apply = do_while_transform_prefix_apply,
1108 .destroy = do_while_transform_destroy,
1109};
1110
1111/** Create a transform that applies its subtransform while an expression on the
1112 * result returns true. Takes a reference to @a xform and @a expr.
1113 * @param[out] out Holds the new transform.
1114 * @param xform The subtransform to apply repeatedly.
1115 * @param expr Applied in the result of each application of @a xform to
1116 * determine whether there will be more.
1117 * @return EOK on success or an error code from errno.h. */
1118int bithenge_do_while_transform(bithenge_transform_t **out,
1119 bithenge_transform_t *xform, bithenge_expression_t *expr)
1120{
1121 int rc;
1122 do_while_transform_t *self = malloc(sizeof(*self));
1123 if (!self) {
1124 rc = ENOMEM;
1125 goto error;
1126 }
1127
1128 rc = bithenge_init_transform(do_while_as_transform(self),
1129 &do_while_transform_ops, 0);
1130 if (rc != EOK)
1131 goto error;
1132
1133 self->expr = expr;
1134 self->xform = xform;
1135 *out = do_while_as_transform(self);
1136 return EOK;
1137
1138error:
1139 free(self);
1140 bithenge_expression_dec_ref(expr);
1141 bithenge_transform_dec_ref(xform);
1142 return rc;
1143}
1144
[0f8062a4]1145/** @}
1146 */
Note: See TracBrowser for help on using the repository browser.