예제 #1
0
        Expression Nullable(IParser parser, Expression var, Type schemaType, bool initialize)
        {
            return(parser.Container(schemaType.GetBondDataType(),
                                    (valueParser, valueType, next, count, arraySegment) =>
            {
                var body = new List <Expression>();

                if (initialize)
                {
                    body.Add(Expression.Assign(var, Expression.Default(var.Type)));
                }

                body.Add(ControlExpression.While(next,
                                                 Value(valueParser, var, valueType, schemaType, initialize: true)));

                return Expression.Block(body);
            }));
        }
예제 #2
0
        Expression Container(IParser parser, RuntimeSchema schema)
        {
            var expectedValueType = schema.HasValue ? schema.TypeDef.element.id : (BondDataType?)null;

            return(parser.Container(expectedValueType,
                                    (valueParser, elementType, next, count, arraySegment) =>
            {
                var body = ControlExpression.While(next,
                                                   Expression.Block(
                                                       writer.WriteItemBegin(),
                                                       schema.HasValue ?
                                                       Value(valueParser, elementType, schema.GetElementSchema()) :
                                                       Value(valueParser, elementType),
                                                       writer.WriteItemEnd()));

                var blob = parser.Blob(count);
                if ((blob != null) || (arraySegment != null))
                {
                    body = PrunedExpression.IfThenElse(
                        Expression.Equal(elementType, Expression.Constant(BondDataType.BT_INT8)),
                        writer.WriteBytes(arraySegment ?? blob),
                        body);

                    // For binary protocols we can write blob directly using protocols's WriteBytes
                    // even if the container is not a blob (blob is BT_LIST of BT_INT8).
                    if (binaryWriter)
                    {
                        body = PrunedExpression.IfThenElse(
                            Expression.Equal(elementType, Expression.Constant(BondDataType.BT_UINT8)),
                            writer.WriteBytes(arraySegment ?? blob),
                            body);
                    }
                }

                return Expression.Block(
                    writer.WriteContainerBegin(count, elementType),
                    body,
                    writer.WriteContainerEnd());
            }));
        }
예제 #3
0
        Expression Map(IParser parser, Expression map, Type schemaType, bool initialize)
        {
            var itemSchemaType = schemaType.GetKeyValueType();

            return(parser.Map(itemSchemaType.Key.GetBondDataType(), itemSchemaType.Value.GetBondDataType(),
                              (keyParser, valueParser, keyType, valueType, nextKey, nextValue, count) =>
            {
                Expression init = Expression.Empty();

                var itemType = map.Type.GetKeyValueType();
                var key = Expression.Variable(itemType.Key, map + "_key");
                var value = Expression.Variable(itemType.Value, map + "_value");

                if (initialize)
                {
                    var cappedCount = Expression.Variable(typeof(int), map + "_count");

                    // TODO: should we use non-default Comparer
                    init = ApplyCountCap(
                        count,
                        cappedCount,
                        DeserializerControls.Active.MaxPreallocatedContainerElements,
                        Expression.Assign(map, newContainer(map.Type, schemaType, cappedCount)));
                }

                var add = map.Type.GetDeclaredProperty(typeof(IDictionary <,>), "Item", value.Type);

                Expression addItem = Expression.Block(
                    Value(keyParser, key, keyType, itemSchemaType.Key, initialize: true),
                    nextValue,
                    Value(valueParser, value, valueType, itemSchemaType.Value, initialize: true),
                    Expression.Assign(Expression.Property(map, add, new Expression[] { key }), value));

                return Expression.Block(
                    new[] { key, value },
                    init,
                    ControlExpression.While(nextKey,
                                            addItem));
            }));
        }
예제 #4
0
        Expression Map(IParser parser, RuntimeSchema schema)
        {
            var expectedValueType = schema.HasValue ? schema.TypeDef.element.id : (BondDataType?)null;
            var expectedKeyType   = schema.HasValue ? schema.TypeDef.key.id : (BondDataType?)null;

            return(parser.Map(expectedKeyType, expectedValueType,
                              (keyParser, valueParser, keyType, valueType, nextKey, nextValue, count) =>
                              Expression.Block(
                                  writer.WriteContainerBegin(count, keyType, valueType),
                                  ControlExpression.While(nextKey,
                                                          Expression.Block(
                                                              writer.WriteItemBegin(),
                                                              schema.HasValue ?
                                                              Value(keyParser, keyType, schema.GetKeySchema()) :
                                                              Value(keyParser, keyType),
                                                              writer.WriteItemEnd(),
                                                              nextValue,
                                                              writer.WriteItemBegin(),
                                                              schema.HasValue ?
                                                              Value(valueParser, valueType, schema.GetElementSchema()) :
                                                              Value(valueParser, valueType),
                                                              writer.WriteItemEnd())),
                                  writer.WriteContainerEnd())));
        }
예제 #5
0
        Expression Container(IParser parser, Expression container, Type schemaType, bool initialize)
        {
            var itemSchemaType = schemaType.GetValueType();

            return(parser.Container(itemSchemaType.GetBondDataType(),
                                    (valueParser, elementType, next, count, arraySegment) =>
            {
                Expression addItem;
                ParameterExpression[] parameters;
                Expression beforeLoop = Expression.Empty();
                Expression afterLoop = Expression.Empty();

                if (schemaType.IsBondBlob())
                {
                    var blob = parser.Blob(count);
                    if (blob != null)
                    {
                        return typeAlias.Assign(container, blob);
                    }

                    // Parser doesn't provide optimized read for blob so we will have to read byte-by-byte.
                    var index = Expression.Variable(typeof(int), "index");
                    var array = Expression.Variable(typeof(byte[]), "array");

                    var cappedCount = Expression.Variable(typeof(int), container + "_count");
                    beforeLoop = ApplyCountCap(
                        count,
                        cappedCount,
                        DeserializerControls.Active.MaxPreallocatedBlobBytes,
                        Expression.Block(
                            Expression.Assign(index, Expression.Constant(0)),
                            Expression.Assign(array, Expression.NewArrayBounds(typeof(byte), cappedCount))));

                    // If parser didn't provide real element count we may need to resize the array
                    var newSize = Expression.Condition(
                        Expression.GreaterThan(index, Expression.Constant(512)),
                        Expression.Multiply(index, Expression.Constant(2)),
                        Expression.Constant(1024));

                    addItem = Expression.Block(
                        Expression.IfThen(
                            Expression.GreaterThanOrEqual(index, Expression.ArrayLength(array)),
                            Expression.Call(null, arrayResize.MakeGenericMethod(typeof(byte)), array, newSize)),
                        valueParser.Scalar(elementType, BondDataType.BT_INT8, value => Expression.Assign(
                                               Expression.ArrayAccess(array, Expression.PostIncrementAssign(index)),
                                               Expression.Convert(value, typeof(byte)))));

                    afterLoop = typeAlias.Assign(
                        container,
                        Expression.New(arraySegmentCtor, array, Expression.Constant(0), index));

                    parameters = new[] { index, array };
                }
                else if (container.Type.IsArray)
                {
                    var arrayElemType = container.Type.GetValueType();
                    var containerResizeMethod = arrayResize.MakeGenericMethod(arrayElemType);

                    if (initialize)
                    {
                        ParameterExpression cappedCount = Expression.Variable(typeof(int), container + "_count");
                        beforeLoop = ApplyCountCap(
                            count,
                            cappedCount,
                            DeserializerControls.Active.MaxPreallocatedContainerElements,
                            Expression.Assign(container, newContainer(container.Type, schemaType, cappedCount)));
                    }

                    if (arrayElemType == typeof(byte))
                    {
                        var parseBlob = parser.Blob(count);
                        if (parseBlob != null)
                        {
                            var blob = Expression.Variable(typeof(ArraySegment <byte>), "blob");
                            return Expression.Block(
                                new[] { blob },
                                beforeLoop,
                                Expression.Assign(blob, parseBlob),
                                Expression.Call(null, bufferBlockCopy, new[]
                            {
                                Expression.Property(blob, "Array"),
                                Expression.Property(blob, "Offset"),
                                container,
                                Expression.Constant(0),
                                count
                            }));
                        }
                    }

                    var i = Expression.Variable(typeof(int), "i");

                    beforeLoop = Expression.Block(
                        beforeLoop,
                        Expression.Assign(i, Expression.Constant(0)));

                    // Resize the array if we've run out of room
                    var maybeResize =
                        Expression.IfThen(
                            Expression.Equal(i, Expression.ArrayLength(container)),
                            Expression.Call(
                                containerResizeMethod,
                                container,
                                Expression.Multiply(
                                    Expression.Condition(
                                        Expression.LessThan(i, Expression.Constant(32)),
                                        Expression.Constant(32),
                                        i),
                                    Expression.Constant(2))));

                    // Puts a single element into the array.
                    addItem = Expression.Block(
                        maybeResize,
                        Value(
                            valueParser,
                            Expression.ArrayAccess(container, i),
                            elementType,
                            itemSchemaType,
                            initialize: true),
                        Expression.PostIncrementAssign(i));

                    // Expanding the array potentially leaves many blank
                    // entries; this resize will get rid of them.
                    afterLoop = Expression.IfThen(
                        Expression.GreaterThan(Expression.ArrayLength(container), i),
                        Expression.Call(containerResizeMethod, container, i));

                    parameters = new[] { i };
                }
                else
                {
                    var item = Expression.Variable(container.Type.GetValueType(), container + "_item");

                    if (initialize)
                    {
                        var cappedCount = Expression.Variable(typeof(int), container + "_count");
                        beforeLoop = ApplyCountCap(
                            count,
                            cappedCount,
                            DeserializerControls.Active.MaxPreallocatedContainerElements,
                            Expression.Assign(container, newContainer(container.Type, schemaType, cappedCount)));
                    }
                    else
                    {
                        var capacity = container.Type.GetDeclaredProperty("Capacity", count.Type);
                        if (capacity != null)
                        {
                            var cappedCount = Expression.Variable(typeof(int), container + "_count");
                            beforeLoop = ApplyCountCap(
                                count,
                                cappedCount,
                                DeserializerControls.Active.MaxPreallocatedContainerElements,
                                Expression.Assign(Expression.Property(container, capacity), cappedCount));
                        }
                    }

                    var add = container.Type.GetMethod(typeof(ICollection <>), "Add", item.Type);

                    addItem = Expression.Block(
                        Value(valueParser, item, elementType, itemSchemaType, initialize: true),
                        Expression.Call(container, add, item));

                    parameters = new[] { item };
                }

                return Expression.Block(
                    parameters,
                    beforeLoop,
                    ControlExpression.While(next,
                                            addItem),
                    afterLoop);
            }));
        }