source: mainline/uspace/lib/bithenge/sequence.c@ 3a7356dc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3a7356dc was 681a985, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

Bithenge: move library to uspace/lib

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