예제 #1
0
        protected override void EmitWrite(AqlaSerializer.Compiler.CompilerContext ctx, AqlaSerializer.Compiler.Local valueFrom)
        {
            var g = ctx.G;

            using (ctx.StartDebugBlockAuto(this))
                using (Compiler.Local value = ctx.GetLocalWithValue(ExpectedType, valueFrom))
                    using (Compiler.Local t = ctx.Local(typeof(System.Type)))
                        using (Compiler.Local length = ctx.Local(typeof(int)))
                            using (var icol = !_protoCompatibility ? ctx.Local(typeof(ICollection)) : null)
                            {
                                ListHelpers.EmitWrite(
                                    ctx.G,
                                    value,
                                    () =>
                                {
                                    g.Assign(icol, value.AsOperand.As(icol.Type));
                                    g.Assign(length, (icol.AsOperand != null).Conditional(icol.AsOperand.Property("Count"), -1));
                                    g.If(length.AsOperand > 0);
                                    {
                                        g.Writer.WriteFieldHeader(ListHelpers.FieldLength, WireType.Variant);
                                        g.Writer.WriteInt32(length);
                                    }
                                    g.End();

                                    if (_writeSubType)
                                    {
                                        g.Assign(t, value.AsOperand.InvokeGetType());
                                        g.If(_concreteTypeDefault != t.AsOperand);
                                        {
                                            g.Writer.WriteFieldHeaderBegin(ListHelpers.FieldSubtype);
                                            _subTypeHelpers.EmitWrite(g, _metaType, value);
                                        }
                                        g.End();
                                    }
                                },
                                    null);
                            }
        }
예제 #2
0
        protected override void EmitRead(AqlaSerializer.Compiler.CompilerContext ctx, AqlaSerializer.Compiler.Local valueFrom)
        {
            var g = ctx.G;

            using (ctx.StartDebugBlockAuto(this))
                using (Compiler.Local value = ctx.GetLocalWithValueForEmitRead(this, valueFrom))
                    using (Compiler.Local result = ctx.Local(_arrayType, true))
                        using (Compiler.Local reservedTrap = ctx.Local(typeof(int)))
                            using (Compiler.Local list = ctx.Local(ctx.MapType(typeof(List <>)).MakeGenericType(_itemType)))
                                using (Compiler.Local index = ctx.Local(typeof(int)))
                                    using (Compiler.Local length = ctx.Local(typeof(int?), true))
                                        using (Compiler.Local oldLen = ctx.Local(typeof(int)))
                                        {
                                            g.Assign(reservedTrap, -1);
                                            _listHelpers.EmitRead(
                                                ctx.G,
                                                (onSuccess, onFail) =>
                                            {
                                                using (ctx.StartDebugBlockAuto(this, "meta"))
                                                {
                                                    g.If(g.ReaderFunc.TryReadFieldHeader_bool(ListHelpers.FieldLength));
                                                    {
                                                        g.Assign(length, g.ReaderFunc.ReadInt32());
                                                        onSuccess();
                                                    }
                                                    g.Else();
                                                    {
                                                        onFail();
                                                    }
                                                    g.End();
                                                }
                                            },
                                                () =>
                                            {
                                                using (ctx.StartDebugBlockAuto(this, "prepareInstance"))
                                                {
                                                    g.If(length.AsOperand >= 0);
                                                    {
                                                        ctx.MarkDebug("// length read, creating instance");
                                                        var lengthValue = length.AsOperand.Property("Value");
                                                        g.If(lengthValue > _readLengthLimit);
                                                        {
                                                            EmitThrowExceededLengthLimit(g, lengthValue, _readLengthLimit);
                                                        }
                                                        g.End();

                                                        EmitRead_CreateInstance(g, value, lengthValue, null, oldLen, result);
                                                        g.Assign(index, oldLen);
                                                    }
                                                    g.Else();
                                                    {
                                                        ctx.MarkDebug("// length read, creating list");
                                                        g.Assign(reservedTrap, g.ReaderFunc.ReserveNoteObject_int());
                                                        g.Assign(list, g.ExpressionFactory.New(list.Type));
                                                    }
                                                    g.End();
                                                }
                                            },
                                                v =>
                                            {
                                                using (ctx.StartDebugBlockAuto(this, "add"))
                                                {
                                                    g.If(result.AsOperand != null);
                                                    {
                                                        g.Assign(result.AsOperand[index], v);
                                                        g.Increment(index);
                                                    }
                                                    g.Else();
                                                    {
                                                        g.Invoke(list, "Add", v);
                                                    }
                                                    g.End();
                                                }
                                            }
                                                );

                                            g.If(result.AsOperand == null);
                                            {
                                                ctx.MarkDebug("// result == null, creating");
                                                EmitRead_CreateInstance(g, value, list.AsOperand.Property("Count"), reservedTrap, oldLen, result);
                                                g.Invoke(list, "CopyTo", result, oldLen);
                                            }
                                            g.End();
                                            if (EmitReadReturnsValue)
                                            {
                                                ctx.LoadValue(result);
                                            }
                                            else
                                            {
                                                g.Assign(value, result);
                                            }
                                        }
        }
        protected override void EmitRead(AqlaSerializer.Compiler.CompilerContext ctx, AqlaSerializer.Compiler.Local valueFrom)
        {
            var g = ctx.G;

            using (ctx.StartDebugBlockAuto(this))
                using (Compiler.Local value = ctx.GetLocalWithValueForEmitRead(this, valueFrom))
                    using (Compiler.Local result = ctx.Local(_arrayType, true))
                        using (Compiler.Local lengthTemp = ctx.Local(typeof(int)))
                            using (Compiler.Local deepestRank = ctx.Local(typeof(int), true))
                                using (Compiler.Local totalLength = ctx.Local(typeof(int)))
                                {
                                    var lengths   = Enumerable.Range(0, _rank).Select(x => g.ctx.Local(typeof(int))).ToArray();
                                    var indexes   = Enumerable.Range(0, _rank).Select(x => g.ctx.Local(typeof(int), true)).ToArray();
                                    var indexesOp = indexes.Select(x => (Operand)x).ToArray();

                                    var deepestRankLength = lengths[lengths.Length - 1];

                                    g.Assign(totalLength, 1);

                                    _listHelpers.EmitRead(
                                        ctx.G,
                                        (onSuccess, onFail) =>
                                    {
                                        using (ctx.StartDebugBlockAuto(this, "meta"))
                                        {
                                            g.If(g.ReaderFunc.TryReadFieldHeader_bool(ListHelpers.FieldLength));
                                            {
                                                g.Assign(lengthTemp, g.ReaderFunc.ReadInt32());
                                                g.Switch(deepestRank);
                                                {
                                                    for (int i = 0; i < _rank; i++)
                                                    {
                                                        g.Case(i);
                                                        {
                                                            g.Assign(lengths[i], lengthTemp);
                                                        }
                                                        g.Break();
                                                    }

                                                    g.DefaultCase();
                                                    EmitThrowWrongRank(g);
                                                }
                                                g.End();
                                                g.Increment(deepestRank);
                                                g.Assign(totalLength, totalLength.AsOperand * lengthTemp.AsOperand);
                                                onSuccess();
                                            }
                                            g.Else();
                                            {
                                                onFail();
                                            }
                                            g.End();
                                        }
                                    },
                                        () =>
                                    {
                                        using (ctx.StartDebugBlockAuto(this, "prepareInstance"))
                                        {
                                            g.If(deepestRank.AsOperand != _rank);
                                            {
                                                EmitThrowWrongRank(g);
                                            }
                                            g.End();

                                            //g.Decrement(deepestRank); - not used

                                            g.If(totalLength.AsOperand > _readLengthLimit);
                                            {
                                                ArrayDecorator.EmitThrowExceededLengthLimit(g, totalLength, _readLengthLimit);
                                            }
                                            g.End();

                                            ctx.MarkDebug("// length read, creating instance");
                                            EmitRead_CreateInstance(g, value, lengths, indexes[0], result);
                                        }
                                    },
                                        v =>
                                    {
                                        using (ctx.StartDebugBlockAuto(this, "add"))
                                        {
                                            g.Assign(result.AsOperand[indexesOp], v);

                                            var newIndex = indexes[_rank - 1];
                                            g.Increment(newIndex);
                                            g.If(newIndex.AsOperand >= deepestRankLength.AsOperand);
                                            {
                                                // unwrapped loop
                                                var breakLabel = g.DefineLabel();
                                                int rankIndex  = _rank - 1;
                                                while (rankIndex > 0)
                                                {
                                                    g.Assign(indexes[rankIndex], 0);
                                                    --rankIndex;
                                                    g.Increment(indexes[rankIndex]);
                                                    g.If(indexes[rankIndex].AsOperand < lengths[rankIndex].AsOperand);
                                                    {
                                                        g.Goto(breakLabel);
                                                    }
                                                    g.End();
                                                }
                                                g.MarkLabel(breakLabel);
                                            }
                                            g.End();
                                        }
                                    });

                                    foreach (Local local in indexes.Concat(lengths))
                                    {
                                        local.Dispose();
                                    }

                                    if (EmitReadReturnsValue)
                                    {
                                        ctx.LoadValue(result);
                                    }
                                    else
                                    {
                                        g.Assign(value, result);
                                    }
                                }
        }
예제 #4
0
        protected override void EmitRead(AqlaSerializer.Compiler.CompilerContext ctx, AqlaSerializer.Compiler.Local valueFrom)
        {
            var g = ctx.G;

            using (ctx.StartDebugBlockAuto(this))
                using (Compiler.Local value = ctx.GetLocalWithValueForEmitRead(this, valueFrom))
                    using (Compiler.Local oldValueForSubTypeHelpers = ctx.Local(value.Type))
                        using (Compiler.Local createdNew = ctx.Local(typeof(bool), true))
                        {
                            bool asList = IsList && !SuppressIList;

                            // can't call clear? => create new!
                            bool forceNewInstance = !AppendToCollection && !asList;

                            ListHelpers.EmitRead(
                                ctx.G,
                                (onSuccess, onFail) =>
                            {
                                using (ctx.StartDebugBlockAuto(this, "readNextMeta"))
                                {
                                    if (_metaType != null)
                                    {
                                        g.If(g.ReaderFunc.TryReadFieldHeader_bool(ListHelpers.FieldSubtype));
                                        {
                                            using (ctx.StartDebugBlockAuto(this, "subtype handler"))
                                            {
                                                g.Assign(oldValueForSubTypeHelpers, forceNewInstance ? null : value.AsOperand);
                                                _subTypeHelpers.EmitTryRead(
                                                    g,
                                                    oldValueForSubTypeHelpers,
                                                    _metaType,
                                                    r =>
                                                {
                                                    using (ctx.StartDebugBlockAuto(this, "subtype handler - read"))
                                                    {
                                                        if (r != null)
                                                        {
                                                            ctx.MarkDebug("// creating list subtype");
                                                            r.Serializer.EmitCreateInstance(ctx);
                                                            ctx.StoreValue(value);
                                                            g.Assign(createdNew, true);
                                                        }
                                                    }
                                                });
                                            }
                                            onSuccess();
                                        }
                                        g.Else();
                                        {
                                            onFail();
                                        }
                                        g.End();
                                    }
                                    else
                                    {
                                        onFail();
                                    }
                                }
                            }
                                ,
                                () =>
                            {
                                using (ctx.StartDebugBlockAuto(this, "prepareInstance"))
                                {
                                    var createInstanceCondition = value.AsOperand == null;

                                    // also create new if should clear existing instance on not lists
                                    if (forceNewInstance)
                                    {
                                        createInstanceCondition = createInstanceCondition || !createdNew.AsOperand;
                                    }

                                    g.If(createInstanceCondition);
                                    {
                                        ctx.MarkDebug("// creating new list");
                                        EmitCreateInstance(ctx);
                                        ctx.StoreValue(value);
                                        g.Reader.NoteObject(value);
                                    }
                                    g.Else();
                                    {
                                        g.If(!createdNew.AsOperand);
                                        {
                                            g.Reader.NoteObject(value);

                                            if (asList && !AppendToCollection)
                                            {
                                                ctx.MarkDebug("// clearing existing list");
                                                // ReSharper disable once PossibleNullReferenceException
                                                g.Invoke(value, "Clear");
                                            }
                                        }
                                        g.End();
                                    }
                                    g.End();
                                }
                            },
                                v =>
                            {
                                // TODO do null checks without allowing user == operators!
                                using (ctx.StartDebugBlockAuto(this, "add"))
                                {
#if DEBUG_COMPILE_2
                                    g.If(v.AsOperand != null);
                                    {
                                        g.ctx.MarkDebug("adding " + v.AsOperand.InvokeToString());
                                    }
                                    g.End();
#endif
                                    if (asList)
                                    {
                                        ctx.MarkDebug("// using Add method");
                                        Operand instance = value;
                                        if (_add != null && !Helpers.IsAssignableFrom(_add.DeclaringType, ExpectedType))
                                        {
                                            instance = instance.Cast(_add.DeclaringType); // TODO optimize to local
                                        }
                                        g.Invoke(instance, "Add", v);
                                    }
                                    else
                                    {
                                        ctx.MarkDebug("// using add delegate");
                                        ctx.LoadAddress(value, ExpectedType);
                                        if (!Helpers.IsAssignableFrom(_add.DeclaringType, ExpectedType))
                                        {
                                            ctx.Cast(_add.DeclaringType);
                                        }
                                        ctx.LoadValue(v);
                                        ctx.EmitCall(this._add);
                                    }
                                }
                            }
                                );
                            if (EmitReadReturnsValue)
                            {
                                ctx.MarkDebug("returning list");
                                ctx.LoadValue(value);
                            }
                        }
        }