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

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

Fix block comment formatting (ccheck).

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