Exemplo n.º 1
0
        Expression Container(IParser parser, Expression container, Type schemaType, bool initialize)
        {
            var itemSchemaType = schemaType.GetValueType();

            return(parser.Container(itemSchemaType.GetBondDataType(),
                                    (valueParser, elementType, next, count) =>
            {
                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");

                    beforeLoop = Expression.Block(
                        Expression.Assign(index, Expression.Constant(0)),
                        Expression.Assign(array, Expression.NewArrayBounds(typeof(byte), count)));

                    // If parser didn't provide real item 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)
                    {
                        beforeLoop =
                            Expression.Assign(container, newContainer(container.Type, schemaType, count));
                    }

                    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)
                    {
                        beforeLoop = Expression.Assign(container, newContainer(container.Type, schemaType, count));
                    }
                    else
                    {
                        var capacity = container.Type.GetDeclaredProperty("Capacity", count.Type);
                        if (capacity != null)
                        {
                            beforeLoop = Expression.Assign(Expression.Property(container, capacity), count);
                        }
                    }

                    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);
            }));
        }