Changeset 3a7356dc in mainline for uspace/lib/bithenge/expression.c


Ignore:
Timestamp:
2012-08-18T03:58:10Z (12 years ago)
Author:
Sean Bartell <wingedtachikoma@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1f9c9a4
Parents:
681a985
Message:

Bithenge: make concatenation lazier

File:
1 edited

Legend:

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

    r681a985 r3a7356dc  
    8888    bithenge_scope_t *scope, bithenge_node_t **out)
    8989{
     90        int rc;
    9091        binary_expression_t *self = expression_as_binary(base);
    9192        bithenge_node_t *a, *b;
    92         int rc = bithenge_expression_evaluate(self->a, scope, &a);
     93        rc = bithenge_expression_evaluate(self->a, scope, &a);
    9394        if (rc != EOK)
    9495                return rc;
    95         rc = bithenge_expression_evaluate(self->b, scope, &b);
    96         if (rc != EOK) {
    97                 bithenge_node_dec_ref(a);
    98                 return rc;
     96        if (self->op != BITHENGE_EXPRESSION_CONCAT) {
     97                rc = bithenge_expression_evaluate(self->b, scope, &b);
     98                if (rc != EOK) {
     99                        bithenge_node_dec_ref(a);
     100                        return rc;
     101                }
    99102        }
    100103
     
    133136                if (bithenge_node_type(a) != BITHENGE_NODE_BLOB)
    134137                        goto error;
    135                 if (bithenge_node_type(b) != BITHENGE_NODE_BLOB)
    136                         goto error;
    137138                break;
    138139        default:
     
    203204                break;
    204205        case BITHENGE_EXPRESSION_CONCAT:
    205                 rc = bithenge_concat_blob(out, bithenge_node_as_blob(a),
    206                     bithenge_node_as_blob(b));
     206                bithenge_expression_inc_ref(self->b);
     207                bithenge_scope_inc_ref(scope);
     208                rc = bithenge_concat_blob_lazy(out, bithenge_node_as_blob(a),
     209                    self->b, scope);
    207210                a = NULL;
    208211                b = NULL;
     
    962965}
    963966
     967
     968
     969/***************** concat_blob                    *****************/
     970
     971typedef struct {
     972        bithenge_blob_t base;
     973        bithenge_blob_t *a, *b;
     974        aoff64_t a_size;
     975        bithenge_expression_t *b_expr;
     976        bithenge_scope_t *scope;
     977} concat_blob_t;
     978
     979static inline concat_blob_t *blob_as_concat(bithenge_blob_t *base)
     980{
     981        return (concat_blob_t *)base;
     982}
     983
     984static inline bithenge_blob_t *concat_as_blob(concat_blob_t *blob)
     985{
     986        return &blob->base;
     987}
     988
     989static int concat_blob_evaluate_b(concat_blob_t *self)
     990{
     991        if (self->b)
     992                return EOK;
     993        bithenge_node_t *b_node;
     994        int rc = bithenge_expression_evaluate(self->b_expr, self->scope,
     995            &b_node);
     996        if (rc != EOK)
     997                return rc;
     998        if (bithenge_node_type(b_node) != BITHENGE_NODE_BLOB) {
     999                bithenge_node_dec_ref(b_node);
     1000                return bithenge_scope_error(self->scope,
     1001                    "Concatenation arguments must be blobs");
     1002        }
     1003        self->b = bithenge_node_as_blob(b_node);
     1004        bithenge_expression_dec_ref(self->b_expr);
     1005        bithenge_scope_dec_ref(self->scope);
     1006        self->b_expr = NULL;
     1007        self->scope = NULL;
     1008        return EOK;
     1009}
     1010
     1011static int concat_blob_size(bithenge_blob_t *base, aoff64_t *size)
     1012{
     1013        concat_blob_t *self = blob_as_concat(base);
     1014        int rc = concat_blob_evaluate_b(self);
     1015        if (rc != EOK)
     1016                return rc;
     1017        rc = bithenge_blob_size(self->b, size);
     1018        *size += self->a_size;
     1019        return rc;
     1020}
     1021
     1022static int concat_blob_read(bithenge_blob_t *base, aoff64_t offset,
     1023    char *buffer, aoff64_t *size)
     1024{
     1025        int rc;
     1026        concat_blob_t *self = blob_as_concat(base);
     1027
     1028        aoff64_t a_size = 0, b_size = 0;
     1029        if (offset < self->a_size) {
     1030                a_size = *size;
     1031                rc = bithenge_blob_read(self->a, offset, buffer, &a_size);
     1032                if (rc != EOK)
     1033                        return rc;
     1034        }
     1035        if (offset + *size > self->a_size) {
     1036                rc = concat_blob_evaluate_b(self);
     1037                if (rc != EOK)
     1038                        return rc;
     1039                b_size = *size - a_size;
     1040                rc = bithenge_blob_read(self->b,
     1041                    offset + a_size - self->a_size, buffer + a_size, &b_size);
     1042                if (rc != EOK)
     1043                        return rc;
     1044        }
     1045        assert(a_size + b_size <= *size);
     1046        *size = a_size + b_size;
     1047        return EOK;
     1048}
     1049
     1050static int concat_blob_read_bits(bithenge_blob_t *base, aoff64_t offset,
     1051    char *buffer, aoff64_t *size, bool little_endian)
     1052{
     1053        int rc;
     1054        concat_blob_t *self = blob_as_concat(base);
     1055
     1056        aoff64_t a_size = 0, b_size = 0;
     1057        if (offset < self->a_size) {
     1058                a_size = *size;
     1059                rc = bithenge_blob_read_bits(self->a, offset, buffer, &a_size,
     1060                    little_endian);
     1061                if (rc != EOK)
     1062                        return rc;
     1063        }
     1064        if (offset + *size > self->a_size) {
     1065                rc = concat_blob_evaluate_b(self);
     1066                if (rc != EOK)
     1067                        return rc;
     1068                b_size = offset + *size - self->a_size;
     1069                rc = bithenge_blob_read_bits(self->b,
     1070                    offset + a_size - self->a_size, buffer + a_size, &b_size,
     1071                    little_endian);
     1072                if (rc != EOK)
     1073                        return rc;
     1074        }
     1075        assert(a_size + b_size <= *size);
     1076        *size = a_size + b_size;
     1077        return EOK;
     1078}
     1079
     1080static void concat_blob_destroy(bithenge_blob_t *base)
     1081{
     1082        concat_blob_t *self = blob_as_concat(base);
     1083        bithenge_blob_dec_ref(self->a);
     1084        bithenge_blob_dec_ref(self->b);
     1085        bithenge_expression_dec_ref(self->b_expr);
     1086        bithenge_scope_dec_ref(self->scope);
     1087        free(self);
     1088}
     1089
     1090static const bithenge_random_access_blob_ops_t concat_blob_ops = {
     1091        .size = concat_blob_size,
     1092        .read = concat_blob_read,
     1093        .read_bits = concat_blob_read_bits,
     1094        .destroy = concat_blob_destroy,
     1095};
     1096
     1097/** Create a concatenated blob. Takes references to @a a and @a b.
     1098 * @param[out] out Holds the new blob.
     1099 * @param a The first blob.
     1100 * @param b The second blob.
     1101 * @return EOK on success or an error code from errno.h. */
     1102int bithenge_concat_blob(bithenge_node_t **out, bithenge_blob_t *a,
     1103    bithenge_blob_t *b)
     1104{
     1105        assert(out);
     1106        assert(a);
     1107        assert(b);
     1108        int rc;
     1109        concat_blob_t *self = malloc(sizeof(*self));
     1110        if (!self) {
     1111                rc = ENOMEM;
     1112                goto error;
     1113        }
     1114
     1115        rc = bithenge_blob_size(a, &self->a_size);
     1116        if (rc != EOK)
     1117                goto error;
     1118
     1119        rc = bithenge_init_random_access_blob(concat_as_blob(self),
     1120            &concat_blob_ops);
     1121        if (rc != EOK)
     1122                goto error;
     1123        self->a = a;
     1124        self->b = b;
     1125        self->b_expr = NULL;
     1126        self->scope = NULL;
     1127        *out = bithenge_blob_as_node(concat_as_blob(self));
     1128        return EOK;
     1129
     1130error:
     1131        bithenge_blob_dec_ref(a);
     1132        bithenge_blob_dec_ref(b);
     1133        free(self);
     1134        return rc;
     1135}
     1136
     1137/** Create a lazy concatenated blob. Takes references to @a a, @a b_expr, and
     1138 * @a scope.
     1139 * @param[out] out Holds the new blob.
     1140 * @param a The first blob.
     1141 * @param b_expr An expression to calculate the second blob.
     1142 * @param scope The scope in which @a b_expr should be evaluated.
     1143 * @return EOK on success or an error code from errno.h. */
     1144int bithenge_concat_blob_lazy(bithenge_node_t **out, bithenge_blob_t *a,
     1145    bithenge_expression_t *b_expr, bithenge_scope_t *scope)
     1146{
     1147        assert(out);
     1148        assert(a);
     1149        assert(b_expr);
     1150        assert(scope);
     1151        int rc;
     1152        concat_blob_t *self = malloc(sizeof(*self));
     1153        if (!self) {
     1154                rc = ENOMEM;
     1155                goto error;
     1156        }
     1157
     1158        rc = bithenge_blob_size(a, &self->a_size);
     1159        if (rc != EOK)
     1160                goto error;
     1161
     1162        rc = bithenge_init_random_access_blob(concat_as_blob(self),
     1163            &concat_blob_ops);
     1164        if (rc != EOK)
     1165                goto error;
     1166        self->a = a;
     1167        self->b = NULL;
     1168        self->b_expr = b_expr;
     1169        self->scope = scope;
     1170        *out = bithenge_blob_as_node(concat_as_blob(self));
     1171        return EOK;
     1172
     1173error:
     1174        bithenge_blob_dec_ref(a);
     1175        bithenge_expression_dec_ref(b_expr);
     1176        bithenge_scope_dec_ref(scope);
     1177        free(self);
     1178        return rc;
     1179}
     1180
    9641181/** @}
    9651182 */
Note: See TracChangeset for help on using the changeset viewer.