source: mainline/uspace/lib/bithenge/src/sequence.c@ 84239b1

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

And there was much fixing.

  • Property mode set to 100644
File size: 29.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 * Sequence transforms.
35 */
36
37#include <stdlib.h>
38#include <bithenge/blob.h>
39#include <bithenge/expression.h>
40#include <bithenge/sequence.h>
41#include <bithenge/tree.h>
42#include "common.h"
43
44
45
46/***************** seq_node *****************/
47
48typedef struct {
49 bithenge_node_t base;
50 const struct seq_node_ops *ops;
51 bithenge_blob_t *blob;
52 bithenge_scope_t *scope;
53 aoff64_t *ends;
54 size_t num_ends;
55 bool end_on_empty;
56 bithenge_int_t num_xforms;
57} seq_node_t;
58
59typedef struct seq_node_ops {
60 errno_t (*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 errno_t 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 errno_t 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
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
114 bithenge_blob_t *subblob = bithenge_node_as_blob(subblob_node);
115 aoff64_t field_size;
116 rc = bithenge_transform_prefix_length(subxform, self->scope,
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
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
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 errno_t seq_node_subtransform(seq_node_t *self, bithenge_node_t **out,
139 size_t index)
140{
141 aoff64_t start_pos;
142 errno_t 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
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
178 aoff64_t size;
179 rc = bithenge_transform_prefix_apply(subxform, self->scope,
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
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 }
193 self->ends[self->num_ends++] = start_pos + size;
194 } else {
195 aoff64_t end_pos;
196 errno_t 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
211 rc = bithenge_transform_apply(subxform, self->scope, blob_node,
212 out);
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 errno_t seq_node_complete(seq_node_t *self, bool *out)
223{
224 aoff64_t blob_size, end_pos;
225 errno_t 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{
237 bithenge_scope_dec_ref(self->scope);
238 bithenge_blob_dec_ref(self->blob);
239 free(self->ends);
240}
241
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
248static bithenge_scope_t *seq_node_scope(seq_node_t *self)
249{
250 return self->scope;
251}
252
253static errno_t seq_node_init(seq_node_t *self, const seq_node_ops_t *ops,
254 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_int_t num_xforms,
255 bool end_on_empty)
256{
257 self->ops = ops;
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;
264 bithenge_blob_inc_ref(blob);
265 self->blob = blob;
266 self->num_xforms = num_xforms;
267 self->num_ends = 0;
268 self->end_on_empty = end_on_empty;
269 self->scope = scope;
270 if (self->scope)
271 bithenge_scope_inc_ref(self->scope);
272 return EOK;
273}
274
275
276
277/***************** bithenge_new_struct *****************/
278
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 errno_t struct_node_for_each(bithenge_node_t *base,
322 bithenge_for_each_func_t func, void *data)
323{
324 errno_t 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 errno_t 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 errno_t 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
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 }
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 errno_t 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 errno_t 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 errno_t rc = bithenge_init_internal_node(struct_as_node(node),
479 &struct_node_ops);
480 if (rc != EOK) {
481 free(node);
482 return rc;
483 }
484 bithenge_scope_t *inner;
485 rc = bithenge_scope_new(&inner, scope);
486 if (rc != EOK) {
487 free(node);
488 return rc;
489 }
490
491 rc = seq_node_init(struct_as_seq(node), &struct_node_seq_ops, inner,
492 blob, self->num_subtransforms, false);
493 if (rc != EOK) {
494 bithenge_scope_dec_ref(inner);
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;
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
510 *out = struct_as_node(node);
511
512 return EOK;
513}
514
515static errno_t 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 errno_t 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 errno_t 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 errno_t 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 errno_t rc = struct_transform_make_node(self, out_node, scope, blob,
547 true);
548 if (rc != EOK)
549 return rc;
550
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 }
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. */
594errno_t bithenge_new_struct(bithenge_transform_t **out,
595 bithenge_named_transform_t *subtransforms)
596{
597 errno_t 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 while (subtransforms[self->num_subtransforms].transform)
610 self->num_subtransforms++;
611 *out = struct_as_transform(self);
612 return EOK;
613error:
614 free_subtransforms(subtransforms);
615 free(self);
616 return rc;
617}
618
619
620
621/***************** bithenge_repeat_transform *****************/
622
623/* TODO: ignore errors */
624
625typedef struct {
626 bithenge_transform_t base;
627 bithenge_expression_t *expr;
628 bithenge_transform_t *xform;
629} repeat_transform_t;
630
631static inline bithenge_transform_t *repeat_as_transform(
632 repeat_transform_t *self)
633{
634 return &self->base;
635}
636
637static inline repeat_transform_t *transform_as_repeat(
638 bithenge_transform_t *base)
639{
640 return (repeat_transform_t *)base;
641}
642
643typedef struct {
644 seq_node_t base;
645 bool prefix;
646 bithenge_int_t count;
647 bithenge_transform_t *xform;
648} repeat_node_t;
649
650static seq_node_t *repeat_as_seq(repeat_node_t *self)
651{
652 return &self->base;
653}
654
655static repeat_node_t *seq_as_repeat(seq_node_t *base)
656{
657 return (repeat_node_t *)base;
658}
659
660static bithenge_node_t *repeat_as_node(repeat_node_t *self)
661{
662 return seq_as_node(repeat_as_seq(self));
663}
664
665static repeat_node_t *node_as_repeat(bithenge_node_t *base)
666{
667 return seq_as_repeat(node_as_seq(base));
668}
669
670static errno_t repeat_node_for_each(bithenge_node_t *base,
671 bithenge_for_each_func_t func, void *data)
672{
673 errno_t rc = EOK;
674 repeat_node_t *self = node_as_repeat(base);
675
676 for (bithenge_int_t i = 0; self->count == -1 || i < self->count; i++) {
677 bithenge_node_t *subxform_result;
678 rc = seq_node_subtransform(repeat_as_seq(self),
679 &subxform_result, i);
680 if ((rc == EINVAL || rc == ENOENT) && self->count == -1) {
681 self->count = i;
682 seq_node_set_num_xforms(repeat_as_seq(self),
683 self->count);
684 rc = EOK;
685 break;
686 }
687 if (rc != EOK)
688 return rc;
689
690 bithenge_node_t *key_node;
691 rc = bithenge_new_integer_node(&key_node, i);
692 if (rc != EOK) {
693 bithenge_node_dec_ref(subxform_result);
694 return rc;
695 }
696 rc = func(key_node, subxform_result, data);
697 if (rc != EOK)
698 return rc;
699 }
700
701 if (!self->prefix) {
702 bool complete;
703 rc = seq_node_complete(repeat_as_seq(self), &complete);
704 if (rc != EOK)
705 return rc;
706 if (!complete)
707 return EINVAL;
708 }
709
710 return rc;
711}
712
713static errno_t repeat_node_get(bithenge_node_t *base, bithenge_node_t *key,
714 bithenge_node_t **out)
715{
716 repeat_node_t *self = node_as_repeat(base);
717
718 if (bithenge_node_type(key) != BITHENGE_NODE_INTEGER) {
719 bithenge_node_dec_ref(key);
720 return ENOENT;
721 }
722
723 bithenge_int_t index = bithenge_integer_node_value(key);
724 bithenge_node_dec_ref(key);
725 if (index < 0 || (self->count != -1 && index >= self->count))
726 return ENOENT;
727 return seq_node_subtransform(repeat_as_seq(self), out, index);
728}
729
730static void repeat_node_destroy(bithenge_node_t *base)
731{
732 repeat_node_t *self = node_as_repeat(base);
733 seq_node_destroy(repeat_as_seq(self));
734 bithenge_transform_dec_ref(self->xform);
735 free(self);
736}
737
738static const bithenge_internal_node_ops_t repeat_node_ops = {
739 .for_each = repeat_node_for_each,
740 .get = repeat_node_get,
741 .destroy = repeat_node_destroy,
742};
743
744static errno_t repeat_node_get_transform(seq_node_t *base,
745 bithenge_transform_t **out, bithenge_int_t index)
746{
747 repeat_node_t *self = seq_as_repeat(base);
748 *out = self->xform;
749 bithenge_transform_inc_ref(*out);
750 return EOK;
751}
752
753static const seq_node_ops_t repeat_node_seq_ops = {
754 .get_transform = repeat_node_get_transform,
755};
756
757static errno_t repeat_transform_make_node(repeat_transform_t *self,
758 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob,
759 bool prefix)
760{
761 bithenge_int_t count = -1;
762 if (self->expr != NULL) {
763 bithenge_node_t *count_node;
764 errno_t rc = bithenge_expression_evaluate(self->expr, scope,
765 &count_node);
766 if (rc != EOK)
767 return rc;
768 if (bithenge_node_type(count_node) != BITHENGE_NODE_INTEGER) {
769 bithenge_node_dec_ref(count_node);
770 return EINVAL;
771 }
772 count = bithenge_integer_node_value(count_node);
773 bithenge_node_dec_ref(count_node);
774 if (count < 0)
775 return EINVAL;
776 }
777
778 repeat_node_t *node = malloc(sizeof(*node));
779 if (!node)
780 return ENOMEM;
781
782 errno_t rc = bithenge_init_internal_node(repeat_as_node(node),
783 &repeat_node_ops);
784 if (rc != EOK) {
785 free(node);
786 return rc;
787 }
788
789 rc = seq_node_init(repeat_as_seq(node), &repeat_node_seq_ops, scope,
790 blob, count, count == -1);
791 if (rc != EOK) {
792 free(node);
793 return rc;
794 }
795
796 bithenge_transform_inc_ref(self->xform);
797 node->xform = self->xform;
798 node->count = count;
799 node->prefix = prefix;
800 *out = repeat_as_node(node);
801 return EOK;
802}
803
804static errno_t repeat_transform_apply(bithenge_transform_t *base,
805 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
806{
807 repeat_transform_t *self = transform_as_repeat(base);
808 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
809 return EINVAL;
810 return repeat_transform_make_node(self, out, scope,
811 bithenge_node_as_blob(in), false);
812}
813
814static errno_t repeat_transform_prefix_apply(bithenge_transform_t *base,
815 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
816 aoff64_t *out_size)
817{
818 repeat_transform_t *self = transform_as_repeat(base);
819 errno_t rc = repeat_transform_make_node(self, out_node, scope, blob, true);
820 if (rc != EOK)
821 return rc;
822
823 if (out_size) {
824 bithenge_int_t count = node_as_repeat(*out_node)->count;
825 if (count != -1) {
826 rc = seq_node_field_offset(node_as_seq(*out_node),
827 out_size, count);
828 if (rc != EOK) {
829 bithenge_node_dec_ref(*out_node);
830 return rc;
831 }
832 } else {
833 *out_size = 0;
834 for (count = 1; ; count++) {
835 aoff64_t size;
836 rc = seq_node_field_offset(
837 node_as_seq(*out_node), &size, count);
838 if (rc == EINVAL || rc == ENOENT)
839 break;
840 if (rc != EOK) {
841 bithenge_node_dec_ref(*out_node);
842 return rc;
843 }
844 *out_size = size;
845 }
846 }
847 }
848 return EOK;
849}
850
851static void repeat_transform_destroy(bithenge_transform_t *base)
852{
853 repeat_transform_t *self = transform_as_repeat(base);
854 bithenge_transform_dec_ref(self->xform);
855 bithenge_expression_dec_ref(self->expr);
856 free(self);
857}
858
859static const bithenge_transform_ops_t repeat_transform_ops = {
860 .apply = repeat_transform_apply,
861 .prefix_apply = repeat_transform_prefix_apply,
862 .destroy = repeat_transform_destroy,
863};
864
865/** Create a transform that applies its subtransform repeatedly. Takes a
866 * reference to @a xform and @a expr.
867 * @param[out] out Holds the new transform.
868 * @param xform The subtransform to apply repeatedly.
869 * @param expr Used to calculate the number of times @a xform will be applied.
870 * May be NULL, in which case @a xform will be applied indefinitely.
871 * @return EOK on success or an error code from errno.h. */
872errno_t bithenge_repeat_transform(bithenge_transform_t **out,
873 bithenge_transform_t *xform, bithenge_expression_t *expr)
874{
875 errno_t rc;
876 repeat_transform_t *self = malloc(sizeof(*self));
877 if (!self) {
878 rc = ENOMEM;
879 goto error;
880 }
881
882 rc = bithenge_init_transform(repeat_as_transform(self),
883 &repeat_transform_ops, 0);
884 if (rc != EOK)
885 goto error;
886
887 self->expr = expr;
888 self->xform = xform;
889 *out = repeat_as_transform(self);
890 return EOK;
891
892error:
893 free(self);
894 bithenge_expression_dec_ref(expr);
895 bithenge_transform_dec_ref(xform);
896 return rc;
897}
898
899
900
901/***************** bithenge_do_while_transform *****************/
902
903typedef struct {
904 bithenge_transform_t base;
905 bithenge_expression_t *expr;
906 bithenge_transform_t *xform;
907} do_while_transform_t;
908
909static inline bithenge_transform_t *do_while_as_transform(
910 do_while_transform_t *self)
911{
912 return &self->base;
913}
914
915static inline do_while_transform_t *transform_as_do_while(
916 bithenge_transform_t *base)
917{
918 return (do_while_transform_t *)base;
919}
920
921typedef struct {
922 seq_node_t base;
923 bithenge_expression_t *expr;
924 bithenge_transform_t *xform;
925 bithenge_int_t count;
926} do_while_node_t;
927
928static seq_node_t *do_while_as_seq(do_while_node_t *self)
929{
930 return &self->base;
931}
932
933static do_while_node_t *seq_as_do_while(seq_node_t *base)
934{
935 return (do_while_node_t *)base;
936}
937
938static bithenge_node_t *do_while_as_node(do_while_node_t *self)
939{
940 return seq_as_node(do_while_as_seq(self));
941}
942
943static do_while_node_t *node_as_do_while(bithenge_node_t *base)
944{
945 return seq_as_do_while(node_as_seq(base));
946}
947
948static errno_t do_while_node_for_each(bithenge_node_t *base,
949 bithenge_for_each_func_t func, void *data)
950{
951 errno_t rc = EOK;
952 do_while_node_t *self = node_as_do_while(base);
953
954 for (bithenge_int_t i = 0; ; i++) {
955 bithenge_node_t *subxform_result;
956 rc = seq_node_subtransform(do_while_as_seq(self),
957 &subxform_result, i);
958 if (rc != EOK)
959 return rc;
960
961 bithenge_node_t *key_node;
962 rc = bithenge_new_integer_node(&key_node, i);
963 if (rc != EOK) {
964 bithenge_node_dec_ref(subxform_result);
965 return rc;
966 }
967 bithenge_node_inc_ref(subxform_result);
968 rc = func(key_node, subxform_result, data);
969 if (rc != EOK) {
970 bithenge_node_dec_ref(subxform_result);
971 return rc;
972 }
973
974 bithenge_scope_t *scope;
975 rc = bithenge_scope_new(&scope,
976 seq_node_scope(do_while_as_seq(self)));
977 if (rc != EOK) {
978 bithenge_node_dec_ref(subxform_result);
979 return rc;
980 }
981 bithenge_scope_set_current_node(scope, subxform_result);
982 bithenge_node_t *expr_result;
983 rc = bithenge_expression_evaluate(self->expr, scope,
984 &expr_result);
985 bithenge_scope_dec_ref(scope);
986 if (rc != EOK)
987 return rc;
988 if (bithenge_node_type(expr_result) != BITHENGE_NODE_BOOLEAN) {
989 bithenge_node_dec_ref(expr_result);
990 return EINVAL;
991 }
992 bool cond = bithenge_boolean_node_value(expr_result);
993 bithenge_node_dec_ref(expr_result);
994 if (!cond) {
995 self->count = i + 1;
996 seq_node_set_num_xforms(do_while_as_seq(self),
997 self->count);
998 break;
999 }
1000 }
1001
1002 return rc;
1003}
1004
1005static void do_while_node_destroy(bithenge_node_t *base)
1006{
1007 do_while_node_t *self = node_as_do_while(base);
1008 seq_node_destroy(do_while_as_seq(self));
1009 bithenge_expression_dec_ref(self->expr);
1010 bithenge_transform_dec_ref(self->xform);
1011 free(self);
1012}
1013
1014static const bithenge_internal_node_ops_t do_while_node_ops = {
1015 .for_each = do_while_node_for_each,
1016 .destroy = do_while_node_destroy,
1017};
1018
1019static errno_t do_while_node_get_transform(seq_node_t *base,
1020 bithenge_transform_t **out, bithenge_int_t index)
1021{
1022 do_while_node_t *self = seq_as_do_while(base);
1023 *out = self->xform;
1024 bithenge_transform_inc_ref(*out);
1025 return EOK;
1026}
1027
1028static const seq_node_ops_t do_while_node_seq_ops = {
1029 .get_transform = do_while_node_get_transform,
1030};
1031
1032static errno_t do_while_transform_make_node(do_while_transform_t *self,
1033 bithenge_node_t **out, bithenge_scope_t *scope, bithenge_blob_t *blob)
1034{
1035 do_while_node_t *node = malloc(sizeof(*node));
1036 if (!node)
1037 return ENOMEM;
1038
1039 errno_t rc = bithenge_init_internal_node(do_while_as_node(node),
1040 &do_while_node_ops);
1041 if (rc != EOK) {
1042 free(node);
1043 return rc;
1044 }
1045
1046 rc = seq_node_init(do_while_as_seq(node), &do_while_node_seq_ops,
1047 scope, blob, -1, false);
1048 if (rc != EOK) {
1049 free(node);
1050 return rc;
1051 }
1052
1053 bithenge_transform_inc_ref(self->xform);
1054 node->xform = self->xform;
1055 bithenge_expression_inc_ref(self->expr);
1056 node->expr = self->expr;
1057 node->count = -1;
1058 *out = do_while_as_node(node);
1059 return EOK;
1060}
1061
1062static errno_t for_each_noop(bithenge_node_t *key, bithenge_node_t *value,
1063 void *data)
1064{
1065 bithenge_node_dec_ref(key);
1066 bithenge_node_dec_ref(value);
1067 return EOK;
1068}
1069
1070static errno_t do_while_transform_prefix_apply(bithenge_transform_t *base,
1071 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
1072 aoff64_t *out_size)
1073{
1074 do_while_transform_t *self = transform_as_do_while(base);
1075 errno_t rc = do_while_transform_make_node(self, out_node, scope, blob);
1076 if (rc != EOK)
1077 return rc;
1078
1079 if (out_size) {
1080 rc = bithenge_node_for_each(*out_node, for_each_noop, NULL);
1081 if (rc != EOK) {
1082 bithenge_node_dec_ref(*out_node);
1083 return rc;
1084 }
1085
1086 rc = seq_node_field_offset(node_as_seq(*out_node), out_size,
1087 node_as_do_while(*out_node)->count);
1088 if (rc != EOK) {
1089 bithenge_node_dec_ref(*out_node);
1090 return rc;
1091 }
1092 }
1093
1094 return EOK;
1095}
1096
1097static void do_while_transform_destroy(bithenge_transform_t *base)
1098{
1099 do_while_transform_t *self = transform_as_do_while(base);
1100 bithenge_transform_dec_ref(self->xform);
1101 bithenge_expression_dec_ref(self->expr);
1102 free(self);
1103}
1104
1105static const bithenge_transform_ops_t do_while_transform_ops = {
1106 .prefix_apply = do_while_transform_prefix_apply,
1107 .destroy = do_while_transform_destroy,
1108};
1109
1110/** Create a transform that applies its subtransform while an expression on the
1111 * result returns true. Takes a reference to @a xform and @a expr.
1112 * @param[out] out Holds the new transform.
1113 * @param xform The subtransform to apply repeatedly.
1114 * @param expr Applied in the result of each application of @a xform to
1115 * determine whether there will be more.
1116 * @return EOK on success or an error code from errno.h. */
1117errno_t bithenge_do_while_transform(bithenge_transform_t **out,
1118 bithenge_transform_t *xform, bithenge_expression_t *expr)
1119{
1120 errno_t rc;
1121 do_while_transform_t *self = malloc(sizeof(*self));
1122 if (!self) {
1123 rc = ENOMEM;
1124 goto error;
1125 }
1126
1127 rc = bithenge_init_transform(do_while_as_transform(self),
1128 &do_while_transform_ops, 0);
1129 if (rc != EOK)
1130 goto error;
1131
1132 self->expr = expr;
1133 self->xform = xform;
1134 *out = do_while_as_transform(self);
1135 return EOK;
1136
1137error:
1138 free(self);
1139 bithenge_expression_dec_ref(expr);
1140 bithenge_transform_dec_ref(xform);
1141 return rc;
1142}
1143
1144/** @}
1145 */
Note: See TracBrowser for help on using the repository browser.