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

Last change on this file since eec201d was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

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