protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) { Type listType; #if NO_GENERICS listType = typeof(BasicList); #else listType = typeof(System.Collections.Generic.List <>).MakeGenericType(itemType); #endif using (Compiler.Local oldArr = ctx.GetLocalWithValue(ExpectedType, valueFrom)) using (Compiler.Local newArr = new Compiler.Local(ctx, ExpectedType)) using (Compiler.Local list = new Compiler.Local(ctx, listType)) { ctx.EmitCtor(listType); ctx.StoreValue(list); ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType); // leave this "using" here, as it can share the "FieldNumber" local with EmitReadList using (Compiler.Local oldLen = new ProtoBuf.Compiler.Local(ctx, typeof(int))) { ctx.LoadLength(oldArr, true); ctx.CopyValue(); ctx.StoreValue(oldLen); ctx.LoadAddress(list, listType); ctx.LoadValue(listType.GetProperty("Count")); ctx.Add(); ctx.CreateArray(itemType, null); // length is on the stack ctx.StoreValue(newArr); ctx.LoadValue(oldLen); Compiler.CodeLabel nothingToCopy = ctx.DefineLabel(); ctx.BranchIfFalse(nothingToCopy, true); ctx.LoadValue(oldArr); ctx.LoadValue(newArr); ctx.LoadValue(oldLen); Type[] argTypes = new Type[] { typeof(Array), typeof(int) }; ctx.EmitCall(ExpectedType.GetMethod("CopyTo", argTypes)); ctx.MarkLabel(nothingToCopy); ctx.LoadValue(list); ctx.LoadValue(newArr); ctx.LoadValue(oldLen); argTypes[0] = ExpectedType; // // prefer: CopyTo(T[], int) MethodInfo copyTo = listType.GetMethod("CopyTo", argTypes); if (copyTo == null) { // fallback: CopyTo(Array, int) argTypes[1] = typeof(Array); copyTo = listType.GetMethod("CopyTo", argTypes); } ctx.EmitCall(copyTo); } ctx.LoadValue(newArr); } }
protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) { Type listType; listType = ctx.MapType(typeof(System.Collections.Generic.List <>)).MakeGenericType(itemType); Type expected = ExpectedType; using (Compiler.Local oldArr = AppendToCollection ? ctx.GetLocalWithValue(expected, valueFrom) : null) using (Compiler.Local newArr = new Compiler.Local(ctx, expected)) using (Compiler.Local list = new Compiler.Local(ctx, listType)) { ctx.EmitCtor(listType); ctx.StoreValue(list); ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType, false); // leave this "using" here, as it can share the "FieldNumber" local with EmitReadList using (Compiler.Local oldLen = AppendToCollection ? new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))) : null) { Type[] copyToArrayInt32Args = new Type[] { ctx.MapType(typeof(Array)), ctx.MapType(typeof(int)) }; if (AppendToCollection) { ctx.LoadLength(oldArr, true); ctx.CopyValue(); ctx.StoreValue(oldLen); ctx.LoadAddress(list, listType); ctx.LoadValue(listType.GetProperty("Count")); ctx.Add(); ctx.CreateArray(itemType, null); // length is on the stack ctx.StoreValue(newArr); ctx.LoadValue(oldLen); Compiler.CodeLabel nothingToCopy = ctx.DefineLabel(); ctx.BranchIfFalse(nothingToCopy, true); ctx.LoadValue(oldArr); ctx.LoadValue(newArr); ctx.LoadValue(0); // index in target ctx.EmitCall(expected.GetMethod("CopyTo", copyToArrayInt32Args)); ctx.MarkLabel(nothingToCopy); ctx.LoadValue(list); ctx.LoadValue(newArr); ctx.LoadValue(oldLen); } else { ctx.LoadAddress(list, listType); ctx.LoadValue(listType.GetProperty("Count")); ctx.CreateArray(itemType, null); ctx.StoreValue(newArr); ctx.LoadAddress(list, listType); ctx.LoadValue(newArr); ctx.LoadValue(0); } copyToArrayInt32Args[0] = expected; // // prefer: CopyTo(T[], int) MethodInfo copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args); if (copyTo == null) { // fallback: CopyTo(Array, int) copyToArrayInt32Args[1] = ctx.MapType(typeof(Array)); copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args); } ctx.EmitCall(copyTo); } ctx.LoadValue(newArr); } }