Changeset 5e718d9 in mainline for uspace/lib/bithenge/transform.c


Ignore:
Timestamp:
2012-08-21T10:04:16Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
67edca6
Parents:
0da6c04 (diff), 6a97f2e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge with upstream (lp:~wtachi/helenos/bithenge)

File:
1 moved

Legend:

Unmodified
Added
Removed
  • uspace/lib/bithenge/transform.c

    r0da6c04 r5e718d9  
    3737#include <assert.h>
    3838#include <errno.h>
     39#include <stdarg.h>
    3940#include <stdlib.h>
    4041#include "blob.h"
     42#include "os.h"
     43#include "print.h"
    4144#include "transform.h"
     45
     46
     47
     48/***************** transform                                 *****************/
    4249
    4350/** Initialize a new transform.
     
    5663        assert(ops->apply || ops->prefix_apply);
    5764        assert(ops->destroy);
     65        if (bithenge_should_fail())
     66                return ENOMEM;
    5867        self->ops = ops;
    5968        self->refs = 1;
     
    137146 * @param[out] out_node Holds the result of applying this transform to the
    138147 * prefix.
    139  * @param[out] out_size Holds the size of the prefix.
     148 * @param[out] out_size Holds the size of the prefix. Can be null, in which
     149 * case the size is not determined.
    140150 * @return EOK on success, ENOTSUP if not supported, or another error code from
    141151 * errno.h. */
     
    152162                return ENOTSUP;
    153163
    154         int rc = bithenge_transform_prefix_length(self, scope, blob, out_size);
     164        aoff64_t size;
     165        int rc = bithenge_transform_prefix_length(self, scope, blob, &size);
    155166        if (rc != EOK)
    156167                return rc;
    157168        bithenge_node_t *prefix_blob;
    158169        bithenge_blob_inc_ref(blob);
    159         rc = bithenge_new_subblob(&prefix_blob, blob, 0, *out_size);
     170        rc = bithenge_new_subblob(&prefix_blob, blob, 0, size);
    160171        if (rc != EOK)
    161172                return rc;
    162173        rc = bithenge_transform_apply(self, scope, prefix_blob, out_node);
    163174        bithenge_node_dec_ref(prefix_blob);
     175        if (out_size)
     176                *out_size = size;
    164177        return rc;
    165178}
     179
     180
     181
     182/***************** scope                                     *****************/
    166183
    167184/** Create a transform scope. It must be dereferenced with @a
    168185 * bithenge_scope_dec_ref after it is used. Takes ownership of nothing.
     186 * @memberof bithenge_scope_t
    169187 * @param[out] out Holds the new scope.
    170188 * @param outer The outer scope, or NULL.
     
    179197                bithenge_scope_inc_ref(outer);
    180198        self->outer = outer;
     199        self->error = NULL;
    181200        self->barrier = false;
    182201        self->num_params = 0;
     
    189208
    190209/** Dereference a transform scope.
    191  * @param self The scope to dereference. */
     210 * @memberof bithenge_scope_t
     211 * @param self The scope to dereference, or NULL. */
    192212void bithenge_scope_dec_ref(bithenge_scope_t *self)
    193213{
     
    201221        bithenge_scope_dec_ref(self->outer);
    202222        free(self->params);
     223        free(self->error);
    203224        free(self);
    204225}
    205226
    206227/** Get the outer scope of a scope, which may be NULL.
     228 * @memberof bithenge_scope_t
    207229 * @param self The scope to examine.
    208230 * @return The outer scope, which may be NULL. */
     
    212234}
    213235
     236/** Get the error message stored in the scope, which may be NULL. The error
     237 * message only exists as long as the scope does.
     238 * @memberof bithenge_scope_t
     239 * @param scope The scope to get the error message from.
     240 * @return The error message, or NULL. */
     241const char *bithenge_scope_get_error(bithenge_scope_t *scope)
     242{
     243        return scope->error;
     244}
     245
     246/** Set the error message for the scope. The error message is stored in the
     247 * outermost scope, but if any scope already has an error message this error
     248 * message is ignored.
     249 * @memberof bithenge_scope_t
     250 * @param scope The scope.
     251 * @param format The format string.
     252 * @return EINVAL normally, or another error code from errno.h. */
     253int bithenge_scope_error(bithenge_scope_t *scope, const char *format, ...)
     254{
     255        if (scope->error)
     256                return EINVAL;
     257        while (scope->outer) {
     258                scope = scope->outer;
     259                if (scope->error)
     260                        return EINVAL;
     261        }
     262        size_t space_left = 256;
     263        scope->error = malloc(space_left);
     264        if (!scope->error)
     265                return ENOMEM;
     266        char *out = scope->error;
     267        va_list ap;
     268        va_start(ap, format);
     269
     270        while (*format) {
     271                if (format[0] == '%' && format[1] == 't') {
     272                        format += 2;
     273                        int rc = bithenge_print_node_to_string(&out,
     274                            &space_left, BITHENGE_PRINT_PYTHON,
     275                            va_arg(ap, bithenge_node_t *));
     276                        if (rc != EOK) {
     277                                va_end(ap);
     278                                return rc;
     279                        }
     280                } else {
     281                        const char *end = str_chr(format, '%');
     282                        if (!end)
     283                                end = format + str_length(format);
     284                        size_t size = min((size_t)(end - format),
     285                            space_left - 1);
     286                        memcpy(out, format, size);
     287                        format = end;
     288                        out += size;
     289                        space_left -= size;
     290                }
     291        }
     292        *out = '\0';
     293
     294        va_end(ap);
     295        return EINVAL;
     296}
     297
    214298/** Get the current node being created, which may be NULL.
     299 * @memberof bithenge_scope_t
    215300 * @param scope The scope to get the current node from.
    216301 * @return The node being created, or NULL. */
     
    223308
    224309/** Set the current node being created. Takes a reference to @a node.
     310 * @memberof bithenge_scope_t
    225311 * @param scope The scope to set the current node in.
    226312 * @param node The current node being created, or NULL. */
     
    233319
    234320/** Get the current input node, which may be NULL.
     321 * @memberof bithenge_scope_t
    235322 * @param scope The scope to get the current input node from.
    236323 * @return The input node, or NULL. */
     
    243330
    244331/** Set the current input node. Takes a reference to @a node.
     332 * @memberof bithenge_scope_t
    245333 * @param scope The scope to set the input node in.
    246334 * @param node The input node, or NULL. */
     
    252340
    253341/** Set a scope as a barrier.
     342 * @memberof bithenge_scope_t
    254343 * @param self The scope to change. */
    255344void bithenge_scope_set_barrier(bithenge_scope_t *self)
     
    260349/** Check whether a scope is a barrier, meaning that variable lookup stops at
    261350 * it.
     351 * @memberof bithenge_scope_t
    262352 * @param self The scope to check.
    263353 * @return Whether the scope is a barrier. */
     
    270360 * bithenge_scope_set_param. This must not be called on a scope that already
    271361 * has parameters.
     362 * @memberof bithenge_scope_t
    272363 * @param scope The scope in which to allocate parameters.
    273364 * @param num_params The number of parameters to allocate.
     
    284375}
    285376
    286 /** Set a parameter. Takes a reference to @a value. Note that range checking is
     377/** Set a parameter. Takes a reference to @a node. Note that range checking is
    287378 * not done in release builds.
     379 * @memberof bithenge_scope_t
    288380 * @param scope The scope in which to allocate parameters.
    289381 * @param i The index of the parameter to set.
    290  * @param value The value to store in the parameter.
     382 * @param node The value to store in the parameter.
    291383 * @return EOK on success or an error code from errno.h. */
    292384int bithenge_scope_set_param( bithenge_scope_t *scope, int i,
     
    295387        assert(scope);
    296388        assert(i >= 0 && i < scope->num_params);
     389        if (bithenge_should_fail()) {
     390                bithenge_node_dec_ref(node);
     391                return ENOMEM;
     392        }
    297393        scope->params[i] = node;
    298394        return EOK;
     
    300396
    301397/** Get a parameter. Note that range checking is not done in release builds.
     398 * @memberof bithenge_scope_t
    302399 * @param scope The scope to get the parameter from.
    303400 * @param i The index of the parameter to set.
     
    318415}
    319416
     417
     418
     419/***************** barrier_transform                         *****************/
     420
    320421typedef struct {
    321422        bithenge_transform_t base;
     
    344445                return rc;
    345446        bithenge_scope_set_barrier(inner_scope);
    346         rc = bithenge_transform_apply(self->transform, scope, in, out);
     447        bithenge_scope_set_in_node(inner_scope, in);
     448        rc = bithenge_transform_apply(self->transform, inner_scope, in, out);
    347449        bithenge_scope_dec_ref(inner_scope);
    348450        return rc;
     
    358460                return rc;
    359461        bithenge_scope_set_barrier(inner_scope);
    360         rc = bithenge_transform_prefix_length(self->transform, scope, in, out);
     462        bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in));
     463        rc = bithenge_transform_prefix_length(self->transform, inner_scope, in,
     464            out);
    361465        bithenge_scope_dec_ref(inner_scope);
    362466        return rc;
     
    373477                return rc;
    374478        bithenge_scope_set_barrier(inner_scope);
    375         rc = bithenge_transform_prefix_apply(self->transform, scope, in,
     479        bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in));
     480        rc = bithenge_transform_prefix_apply(self->transform, inner_scope, in,
    376481            out_node, out_length);
    377482        bithenge_scope_dec_ref(inner_scope);
     
    393498};
    394499
     500/** Set the subtransform of a barrier transform. This must be done before the
     501 * barrier transform is used. Takes a reference to @a transform.
     502 * @param base The barrier transform.
     503 * @param transform The subtransform to use for all operations.
     504 * @return EOK on success or an error code from errno.h. */
     505int bithenge_barrier_transform_set_subtransform(bithenge_transform_t *base,
     506    bithenge_transform_t *transform)
     507{
     508        assert(transform);
     509        assert(bithenge_transform_num_params(transform) == 0);
     510
     511        if (bithenge_should_fail()) {
     512                bithenge_transform_dec_ref(transform);
     513                return ENOMEM;
     514        }
     515
     516        barrier_transform_t *self = transform_as_barrier(base);
     517        assert(!self->transform);
     518        self->transform = transform;
     519        return EOK;
     520}
     521
    395522/** Create a wrapper transform that creates a new scope. This ensures nothing
    396523 * from the outer scope is passed in, other than parameters. The wrapper may
    397  * have a different value for num_params. Takes a reference to @a transform,
    398  * which it will use for all operations.
     524 * have a different value for num_params. The subtransform must be set with @a
     525 * bithenge_barrier_transform_set_subtransform before the result is used.
    399526 * @param[out] out Holds the created transform.
    400  * @param transform The transform to wrap.
    401527 * @param num_params The number of parameters to require, which may be 0.
    402528 * @return EOK on success or an error code from errno.h. */
    403 int bithenge_new_barrier_transform(bithenge_transform_t **out,
    404     bithenge_transform_t *transform, int num_params)
    405 {
    406         assert(transform);
    407         assert(bithenge_transform_num_params(transform) == 0);
    408 
     529int bithenge_new_barrier_transform(bithenge_transform_t **out, int num_params)
     530{
    409531        int rc;
    410532        barrier_transform_t *self = malloc(sizeof(*self));
     
    417539        if (rc != EOK)
    418540                goto error;
    419         self->transform = transform;
     541        self->transform = NULL;
    420542        *out = barrier_as_transform(self);
    421543        return EOK;
    422544error:
    423         bithenge_transform_dec_ref(transform);
    424545        free(self);
    425546        return rc;
     
    480601{
    481602        char buffer;
    482         *out_size = 1;
    483         int rc = bithenge_blob_read_bits(blob, 0, &buffer, out_size, true);
    484         if (rc != EOK)
    485                 return rc;
    486         if (*out_size != 1)
    487                 return EINVAL;
     603        aoff64_t size = 1;
     604        int rc = bithenge_blob_read_bits(blob, 0, &buffer, &size, true);
     605        if (rc != EOK)
     606                return rc;
     607        if (size != 1)
     608                return EINVAL;
     609        if (out_size)
     610                *out_size = size;
    488611        return bithenge_new_boolean_node(out_node, (buffer & 1) != 0);
    489612}
     
    758881}
    759882
     883/** @cond internal */
    760884#define MAKE_UINT_TRANSFORM(NAME, TYPE, ENDIAN, PREFIX_LENGTH_FUNC)            \
    761885        static int NAME##_apply(bithenge_transform_t *self,                    \
     
    795919MAKE_UINT_TRANSFORM(uint32le, uint32_t, uint32_t_le2host, prefix_length_4);
    796920MAKE_UINT_TRANSFORM(uint32be, uint32_t, uint32_t_be2host, prefix_length_4);
    797 MAKE_UINT_TRANSFORM(uint64le, uint64_t, uint32_t_le2host, prefix_length_8);
    798 MAKE_UINT_TRANSFORM(uint64be, uint64_t, uint32_t_be2host, prefix_length_8);
     921MAKE_UINT_TRANSFORM(uint64le, uint64_t, uint64_t_le2host, prefix_length_8);
     922MAKE_UINT_TRANSFORM(uint64be, uint64_t, uint64_t_be2host, prefix_length_8);
     923/** @endcond */
    799924
    800925
     
    822947                return EINVAL;
    823948
    824         *out_size = num_bits;
     949        aoff64_t size = num_bits;
    825950        uint8_t buffer[sizeof(bithenge_int_t)];
    826         rc = bithenge_blob_read_bits(blob, 0, (char *)buffer, out_size,
     951        rc = bithenge_blob_read_bits(blob, 0, (char *)buffer, &size,
    827952            little_endian);
    828953        if (rc != EOK)
    829954                return rc;
    830         if (*out_size != (aoff64_t)num_bits)
    831                 return EINVAL;
     955        if (size != (aoff64_t)num_bits)
     956                return EINVAL;
     957        if (out_size)
     958                *out_size = size;
    832959
    833960        bithenge_int_t result = 0;
     
    9481075bithenge_named_transform_t *bithenge_primitive_transforms = primitive_transforms;
    9491076
    950 typedef struct {
    951         bithenge_transform_t base;
    952         bithenge_transform_t **xforms;
    953         size_t num;
    954 } compose_transform_t;
    955 
    956 static bithenge_transform_t *compose_as_transform(compose_transform_t *xform)
    957 {
    958         return &xform->base;
    959 }
    960 
    961 static compose_transform_t *transform_as_compose(bithenge_transform_t *xform)
    962 {
    963         return (compose_transform_t *)xform;
    964 }
    965 
    966 static int compose_apply(bithenge_transform_t *base, bithenge_scope_t *scope,
    967     bithenge_node_t *in, bithenge_node_t **out)
    968 {
    969         int rc;
    970         compose_transform_t *self = transform_as_compose(base);
    971         bithenge_node_inc_ref(in);
    972 
    973         /* i ranges from (self->num - 1) to 0 inside the loop. */
    974         for (size_t i = self->num; i--; ) {
    975                 bithenge_node_t *tmp;
    976                 rc = bithenge_transform_apply(self->xforms[i], scope, in,
    977                     &tmp);
    978                 bithenge_node_dec_ref(in);
    979                 if (rc != EOK)
    980                         return rc;
    981                 in = tmp;
    982         }
    983 
    984         *out = in;
    985         return rc;
    986 }
    987 
    988 static int compose_prefix_length(bithenge_transform_t *base,
    989     bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
    990 {
    991         compose_transform_t *self = transform_as_compose(base);
    992         return bithenge_transform_prefix_length(self->xforms[self->num - 1],
    993             scope, blob, out);
    994 }
    995 
    996 static void compose_destroy(bithenge_transform_t *base)
    997 {
    998         compose_transform_t *self = transform_as_compose(base);
    999         for (size_t i = 0; i < self->num; i++)
    1000                 bithenge_transform_dec_ref(self->xforms[i]);
    1001         free(self->xforms);
    1002         free(self);
    1003 }
    1004 
    1005 static const bithenge_transform_ops_t compose_transform_ops = {
    1006         .apply = compose_apply,
    1007         .prefix_length = compose_prefix_length,
    1008         .destroy = compose_destroy,
    1009 };
    1010 
    1011 /** Create a composition of multiple transforms. When the result is applied to a
    1012  * node, each transform is applied in turn, with the last transform applied
    1013  * first. @a xforms may contain any number of transforms or no transforms at
    1014  * all. This function takes ownership of @a xforms and the references therein.
    1015  * @param[out] out Holds the result.
    1016  * @param[in] xforms The transforms to apply.
    1017  * @param num The number of transforms.
    1018  * @return EOK on success or an error code from errno.h. */
    1019 int bithenge_new_composed_transform(bithenge_transform_t **out,
    1020     bithenge_transform_t **xforms, size_t num)
    1021 {
    1022         if (num == 0) {
    1023                 /* TODO: optimize */
    1024         } else if (num == 1) {
    1025                 *out = xforms[0];
    1026                 free(xforms);
    1027                 return EOK;
    1028         }
    1029 
    1030         int rc;
    1031         compose_transform_t *self = malloc(sizeof(*self));
    1032         if (!self) {
    1033                 rc = ENOMEM;
    1034                 goto error;
    1035         }
    1036         rc = bithenge_init_transform(compose_as_transform(self),
    1037             &compose_transform_ops, 0);
    1038         if (rc != EOK)
    1039                 goto error;
    1040         self->xforms = xforms;
    1041         self->num = num;
    1042         *out = compose_as_transform(self);
    1043         return EOK;
    1044 error:
    1045         for (size_t i = 0; i < num; i++)
    1046                 bithenge_transform_dec_ref(xforms[i]);
    1047         free(xforms);
    1048         free(self);
    1049         return rc;
    1050 }
    1051 
    10521077/** @}
    10531078 */
Note: See TracChangeset for help on using the changeset viewer.