using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo(MsgPack.CompiledPacker.MethodBuilderPacker.AssemblyName)]
//========================================================================================================
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//using NUnit.Framework;
namespace Test
{
using System;
using System.Collections.Generic;
using System.Linq;
using Test.Share;
using MsgPack;
using Microshaoft;
//using System.Diagnostics;
//using Microsoft.VisualStudio.TestTools.UnitTesting;
//[TestFixture]
public class Class1
{
static void Main(string[] args)
{
Class1 c = new Class1();
int iterations = 1000;
CodeTimer.ParallelTime
(
"MsgPack ObjectPacker 并行测试",
iterations,
() =>
{
c.Test_ObjectPacker();
}
);
CodeTimer.Time
(
"MsgPack ObjectPacker 串行测试",
iterations,
() =>
{
c.Test_ObjectPacker();
}
);
CodeTimer.ParallelTime
(
"MsgPack CompiledPacker 并行测试",
iterations,
() =>
{
c.Test_CompiledPacker();
}
);
CodeTimer.Time
(
"MsgPack CompiledPacker 串行测试",
iterations,
() =>
{
c.Test_CompiledPacker();
}
);
//CodeTimer.ParallelTime
// (
// "MsgPack BoxingPacker 并行测试",
// iterations,
// () =>
// {
// c.Test_BoxingPacker();
// }
// );
//CodeTimer.Time
// (
// "MsgPack BoxingPacker 串行测试",
// iterations,
// () =>
// {
// c.Test_BoxingPacker();
// }
// );
CodeTimer.ParallelTime
(
"MsgPack ObjectPacker/CompiledPacker 并行测试",
iterations,
() =>
{
c.Test_HybridPacker();
}
);
CodeTimer.Time
(
"MsgPack ObjectPacker/CompiledPacker 串行测试",
iterations,
() =>
{
c.Test_HybridPacker();
}
);
Console.WriteLine("Hello World");
Console.WriteLine(Environment.Version.ToString());
Console.ReadLine();
}
public void Test_HybridPacker()
{
ObjectMsgPackHeader header = new ObjectMsgPackHeader();
header.From = "Microshaoft";
header.ToList = new string[] { "m1", "m2", "m3" };
//header.Instance = header;
ObjectMsgPackBody body = new ObjectMsgPackBody();
body.Parameter1 = "asdasdas";
body.Parameter2 = 1000;
body.ParameterX = new List<string>();
body.ParameterX.Add("aaaaa");
body.ParameterX.Add("bbbbb");
//body.Instance = body;
byte[] buffer;
ObjectMsgPack message = new ObjectMsgPack();
message.Header = new CompiledPacker().Pack(header);
message.Body = new ObjectPacker().Pack(body);
message.SenderID = "asdasd";
message.Signature = new byte[10];
message.TimeStamp = "2012-03-22";
buffer = new ObjectPacker().Pack(message);
//Console.WriteLine("HybridPacker Buffer.Length {0}", buffer.Length);
ObjectMsgPack x = new ObjectPacker().Unpack<ObjectMsgPack>(buffer);
ObjectMsgPackHeader y = new CompiledPacker().Unpack<ObjectMsgPackHeader>(x.Header);
ObjectMsgPackBody z = new ObjectPacker().Unpack<ObjectMsgPackBody>(x.Body);
Print(x, y, z);
}
public void Test_BoxingPacker()
{
ObjectMsgPackHeader header = new ObjectMsgPackHeader();
header.From = "Microshaoft";
header.ToList = new string[] { "m1", "m2", "m3" };
//header.Instance = header;
ObjectMsgPackBody body = new ObjectMsgPackBody();
body.Parameter1 = "asdasdas";
body.Parameter2 = 1000;
body.ParameterX = new List<string>();
body.ParameterX.Add("aaaaa");
body.ParameterX.Add("bbbbb");
//body.Instance = body;
byte[] buffer;
ObjectMsgPack message = new ObjectMsgPack();
message.Header = new BoxingPacker().Pack(header);
message.Body = new BoxingPacker().Pack(body);
message.SenderID = "asdasd";
message.Signature = new byte[10];
message.TimeStamp = "2012-03-22";
buffer = new BoxingPacker().Pack(message);
//Console.WriteLine("BoxingPacker Buffer.Length {0}", buffer.Length);
ObjectMsgPack x = (ObjectMsgPack) new BoxingPacker().Unpack(buffer);
ObjectMsgPackHeader y = (ObjectMsgPackHeader) new BoxingPacker().Unpack(x.Header);
ObjectMsgPackBody z = (ObjectMsgPackBody) new BoxingPacker().Unpack(x.Body);
Print(x, y, z);
}
public void Test_CompiledPacker()
{
ObjectMsgPackHeader header = new ObjectMsgPackHeader();
header.From = "Microshaoft";
header.ToList = new string[] { "m1", "m2", "m3" };
//header.Instance = header;
ObjectMsgPackBody body = new ObjectMsgPackBody();
body.Parameter1 = "asdasdas";
body.Parameter2 = 1000;
body.ParameterX = new List<string>();
body.ParameterX.Add("aaaaa");
body.ParameterX.Add("bbbbb");
//body.Instance = body;
byte[] buffer;
ObjectMsgPack message = new ObjectMsgPack();
message.Header = new CompiledPacker().Pack(header);
message.Body = new CompiledPacker().Pack(body);
message.SenderID = "asdasd";
message.Signature = new byte[10];
message.TimeStamp = "2012-03-22";
buffer = new CompiledPacker().Pack(message);
//Console.WriteLine("CompiledPacker Buffer.Length {0}", buffer.Length);
ObjectMsgPack x = new CompiledPacker().Unpack<ObjectMsgPack>(buffer);
ObjectMsgPackHeader y = new CompiledPacker().Unpack<ObjectMsgPackHeader>(x.Header);
ObjectMsgPackBody z = new CompiledPacker().Unpack<ObjectMsgPackBody>(x.Body);
Print(x, y, z);
}
public void Test_ObjectPacker()
{
ObjectMsgPackHeader header = new ObjectMsgPackHeader();
header.From = "Microshaoft";
header.ToList = new string[] { "m1", "m2", "m3" };
//header.Instance = header;
ObjectMsgPackBody body = new ObjectMsgPackBody();
body.Parameter1 = "asdasdas";
body.Parameter2 = 1000;
body.ParameterX = new List<string>();
body.ParameterX.Add("aaaaa");
body.ParameterX.Add("bbbbb");
//body.Instance = body;
byte[] buffer;
ObjectMsgPack message = new ObjectMsgPack();
message.Header = new ObjectPacker().Pack(header);
message.Body = new ObjectPacker().Pack(body);
message.SenderID = "asdasd";
message.Signature = new byte[10];
message.TimeStamp = "2012-03-22";
buffer = new ObjectPacker().Pack(message);
//Console.WriteLine("ObjectPacker Buffer.Length {0}", buffer.Length);
ObjectMsgPack x = new ObjectPacker().Unpack<ObjectMsgPack>(buffer);
ObjectMsgPackHeader y = new ObjectPacker().Unpack<ObjectMsgPackHeader>(x.Header);
ObjectMsgPackBody z = new ObjectPacker().Unpack<ObjectMsgPackBody>(x.Body);
Print(x, y, z);
}
public void Print(ObjectMsgPack x, ObjectMsgPackHeader y, ObjectMsgPackBody z)
{
return;
Console.WriteLine(x.SenderID);
Console.WriteLine(x.Signature.Length);
Console.WriteLine(x.TimeStamp);
Console.WriteLine(y.From);
y.ToList.ToList().ForEach
(
s =>
{
Console.WriteLine(s);
}
);
Console.WriteLine(z.Parameter1);
Console.WriteLine(z.Parameter12);
Console.WriteLine(z.FF.F1);
Console.WriteLine(z.FF.F2);
z.Parameter3.ToList().ForEach
(
s =>
{
Console.WriteLine(s);
}
);
}
}
}
namespace Microshaoft
{
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
public static class CodeTimer
{
public static void Initialize()
{
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Time("", 1, () => { });
}
public static void ParallelTime(string name, int iteration, Action action)
{
if (string.IsNullOrEmpty(name))
{
return;
}
// 1.
ConsoleColor currentForeColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(name);
// 2.
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
int[] gcCounts = new int[GC.MaxGeneration + 1];
for (int i = 0; i <= GC.MaxGeneration; i++)
{
gcCounts[i] = GC.CollectionCount(i);
}
// 3.
Stopwatch watch = new Stopwatch();
watch.Start();
ulong cycleCount = GetCycleCount();
Parallel.For
(
0
, iteration
, i =>
{
action();
}
);
ulong cpuCycles = GetCycleCount() - cycleCount;
watch.Stop();
// 4.
Console.ForegroundColor = currentForeColor;
Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0"));
// 5.
for (int i = 0; i <= GC.MaxGeneration; i++)
{
int count = GC.CollectionCount(i) - gcCounts[i];
Console.WriteLine("\tGen " + i + ": \t\t" + count);
}
Console.WriteLine();
}
public static void Time(string name, int iteration, Action action)
{
if (string.IsNullOrEmpty(name))
{
return;
}
// 1.
ConsoleColor currentForeColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(name);
// 2.
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
int[] gcCounts = new int[GC.MaxGeneration + 1];
for (int i = 0; i <= GC.MaxGeneration; i++)
{
gcCounts[i] = GC.CollectionCount(i);
}
// 3.
Stopwatch watch = new Stopwatch();
watch.Start();
ulong cycleCount = GetCycleCount();
for (int i = 0; i < iteration; i++)
{
action();
}
ulong cpuCycles = GetCycleCount() - cycleCount;
watch.Stop();
// 4.
Console.ForegroundColor = currentForeColor;
Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0"));
// 5.
for (int i = 0; i <= GC.MaxGeneration; i++)
{
int count = GC.CollectionCount(i) - gcCounts[i];
Console.WriteLine("\tGen " + i + ": \t\t" + count);
}
Console.WriteLine();
}
private static ulong GetCycleCount()
{
ulong cycleCount = 0;
QueryThreadCycleTime(GetCurrentThread(), ref cycleCount);
return cycleCount;
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulong cycleTime);
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThread();
}
}
//===============================================================================================================
namespace Test.Share
{
using System;
using System.Collections.Generic;
public class ObjectMsgPack
{
public string SenderID;
public string TimeStamp;
public byte[] Signature;
public byte[] Header;
public byte[] Body;
}
public class ObjectMsgPackHeader
{
//public ObjectMsgPack Container;
//public ObjectMsgPackHeader Instance;
public string From;
public string[] ToList;
}
public class ObjectMsgPackBody
{
//public ObjectMsgPack Container;
//public ObjectMsgPackBody Instance;
public string Parameter1 = "aaaa";
public int Parameter2 = 100;
public string Parameter3 = "aaaa";
public int Parameter4 = 100;
public string Parameter5 = "aaaa";
public int Parameter6 = 100;
public string Parameter7 = "aaaa";
public int Parameter8 = 100;
public string Parameter9 = "aaaa";
public int Parameter10 = 100;
public string Parameter11 = "aaaa";
public int Parameter12 = -101;
public List<string> ParameterX;
public ComplexType FF = new ComplexType();
}
public class ComplexType
{
public string F1 = "asdasd";
public DateTime F2 = DateTime.Parse("2012-03-30 00:00:00.00000");
}
}
//================================================================================================
namespace MsgPack
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
public enum TypePrefixes : byte
{
PositiveFixNum = 0x00, // 0x00 - 0x7f
NegativeFixNum = 0xe0, // 0xe0 - 0xff
Nil = 0xc0,
False = 0xc2,
True = 0xc3,
Float = 0xca,
Double = 0xcb,
UInt8 = 0xcc,
UInt16 = 0xcd,
UInt32 = 0xce,
UInt64 = 0xcf,
Int8 = 0xd0,
Int16 = 0xd1,
Int32 = 0xd2,
Int64 = 0xd3,
Raw16 = 0xda,
Raw32 = 0xdb,
Array16 = 0xdc,
Array32 = 0xdd,
Map16 = 0xde,
Map32 = 0xdf,
FixRaw = 0xa0, // 0xa0 - 0xbf
FixArray = 0x90, // 0x90 - 0x9f
FixMap = 0x80, // 0x80 - 0x8f
}
}
namespace MsgPack
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Collections.Generic;
using System.Reflection;
public class ReflectionCacheEntry
{
const BindingFlags FieldBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.SetField;
public ReflectionCacheEntry(Type t)
{
FieldInfo[] fields = t.GetFields(FieldBindingFlags);
IDictionary<string, FieldInfo> map = new Dictionary<string, FieldInfo>(fields.Length);
for (int i = 0; i < fields.Length; i++)
{
FieldInfo f = fields[i];
string name = f.Name;
int pos;
if (name[0] == '<' && (pos = name.IndexOf('>')) > 1)
{
name = name.Substring(1, pos - 1); // Auto-Property (\<.+\>) <ab>
}
map[name] = f;
}
FieldMap = map;
}
public IDictionary<string, FieldInfo> FieldMap { get; private set; }
}
}
namespace MsgPack
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Collections.Generic;
public static class ReflectionCache
{
static Dictionary<Type, ReflectionCacheEntry> _cache;
static ReflectionCache()
{
_cache = new Dictionary<Type, ReflectionCacheEntry>();
}
public static ReflectionCacheEntry Lookup(Type type)
{
ReflectionCacheEntry entry;
lock (_cache)
{
if (_cache.TryGetValue(type, out entry))
{
return entry;
}
}
entry = new ReflectionCacheEntry(type);
lock (_cache)
{
_cache[type] = entry;
}
return entry;
}
public static void RemoveCache(Type type)
{
lock (_cache)
{
_cache.Remove(type);
}
}
public static void Clear()
{
lock (_cache)
{
_cache.Clear();
}
}
}
}
namespace MsgPack
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
public class ObjectPacker
{
byte[] _buf = new byte[64];
Encoding _encoding = Encoding.UTF8;
static Dictionary<Type, PackDelegate> PackerMapping;
static Dictionary<Type, UnpackDelegate> UnpackerMapping;
delegate void PackDelegate(ObjectPacker packer, MsgPackWriter writer, object o);
delegate object UnpackDelegate(ObjectPacker packer, MsgPackReader reader);
static ObjectPacker()
{
PackerMapping = new Dictionary<Type, PackDelegate>();
UnpackerMapping = new Dictionary<Type, UnpackDelegate>();
PackerMapping.Add(typeof(string), StringPacker);
UnpackerMapping.Add(typeof(string), StringUnpacker);
}
public byte[] Pack(object o)
{
using (MemoryStream ms = new MemoryStream())
{
Pack(ms, o);
return ms.ToArray();
}
}
public void Pack(Stream strm, object o)
{
if (o != null && o.GetType().IsPrimitive)
throw new NotSupportedException();
MsgPackWriter writer = new MsgPackWriter(strm);
Pack(writer, o);
}
void Pack(MsgPackWriter writer, object o)
{
if (o == null)
{
writer.WriteNil();
return;
}
Type t = o.GetType();
if (t.IsPrimitive)
{
if (t.Equals(typeof(int)))
{
writer.Write((int)o);
}
else if (t.Equals(typeof(uint)))
{
writer.Write((uint)o);
}
else if (t.Equals(typeof(float)))
{
writer.Write((float)o);
}
else if (t.Equals(typeof(double)))
{
writer.Write((double)o);
}
else if (t.Equals(typeof(long)))
{
writer.Write((long)o);
}
else if (t.Equals(typeof(ulong)))
{
writer.Write((ulong)o);
}
else if (t.Equals(typeof(bool)))
{
writer.Write((bool)o);
}
else if (t.Equals(typeof(byte)))
{
writer.Write((byte)o);
}
else if (t.Equals(typeof(sbyte)))
{
writer.Write((sbyte)o);
}
else if (t.Equals(typeof(short)))
{
writer.Write((short)o);
}
else if (t.Equals(typeof(ushort)))
{
writer.Write((ushort)o);
}
else if (t.Equals(typeof(char)))
{
writer.Write((ushort)(char)o);
}
else
{
throw new NotSupportedException();
}
return;
}
PackDelegate packer;
if (PackerMapping.TryGetValue(t, out packer))
{
packer(this, writer, o);
return;
}
if (t.IsArray)
{
Array ary = (Array)o;
writer.WriteArrayHeader(ary.Length);
for (int i = 0; i < ary.Length; i++)
Pack(writer, ary.GetValue(i));
return;
}
ReflectionCacheEntry entry = ReflectionCache.Lookup(t);
writer.WriteMapHeader(entry.FieldMap.Count);
foreach (KeyValuePair<string, FieldInfo> pair in entry.FieldMap)
{
writer.Write(pair.Key, _buf);
object v = pair.Value.GetValue(o);
if (pair.Value.FieldType.IsInterface && v != null)
{
writer.WriteArrayHeader(2);
writer.Write(v.GetType().FullName);
}
Pack(writer, v);
}
}
public T Unpack<T>(byte[] buf)
{
return Unpack<T>(buf, 0, buf.Length);
}
public T Unpack<T>(byte[] buf, int offset, int size)
{
using (MemoryStream ms = new MemoryStream(buf, offset, size))
{
return Unpack<T>(ms);
}
}
public T Unpack<T>(Stream strm)
{
if (typeof(T).IsPrimitive)
throw new NotSupportedException();
MsgPackReader reader = new MsgPackReader(strm);
return (T)Unpack(reader, typeof(T));
}
public object Unpack(Type type, byte[] buf)
{
return Unpack(type, buf, 0, buf.Length);
}
public object Unpack(Type type, byte[] buf, int offset, int size)
{
using (MemoryStream ms = new MemoryStream(buf, offset, size))
{
return Unpack(type, ms);
}
}
public object Unpack(Type type, Stream strm)
{
if (type.IsPrimitive)
throw new NotSupportedException();
MsgPackReader reader = new MsgPackReader(strm);
return Unpack(reader, type);
}
object Unpack(MsgPackReader reader, Type t)
{
if (t.IsPrimitive)
{
if (!reader.Read()) throw new FormatException();
if (t.Equals(typeof(int)) && reader.IsSigned()) return reader.ValueSigned;
else if (t.Equals(typeof(uint)) && reader.IsUnsigned()) return reader.ValueUnsigned;
else if (t.Equals(typeof(float)) && reader.Type == TypePrefixes.Float) return reader.ValueFloat;
else if (t.Equals(typeof(double)) && reader.Type == TypePrefixes.Double) return reader.ValueDouble;
else if (t.Equals(typeof(long)))
{
if (reader.IsSigned64())
return reader.ValueSigned64;
if (reader.IsSigned())
return (long)reader.ValueSigned;
}
else if (t.Equals(typeof(ulong)))
{
if (reader.IsUnsigned64())
return reader.ValueUnsigned64;
if (reader.IsUnsigned())
return (ulong)reader.ValueUnsigned;
}
else if (t.Equals(typeof(bool)) && reader.IsBoolean()) return (reader.Type == TypePrefixes.True);
else if (t.Equals(typeof(byte)) && reader.IsUnsigned()) return (byte)reader.ValueUnsigned;
else if (t.Equals(typeof(sbyte)) && reader.IsSigned()) return (sbyte)reader.ValueSigned;
else if (t.Equals(typeof(short)) && reader.IsSigned()) return (short)reader.ValueSigned;
else if (t.Equals(typeof(ushort)) && reader.IsUnsigned()) return (ushort)reader.ValueUnsigned;
else if (t.Equals(typeof(char)) && reader.IsUnsigned()) return (char)reader.ValueUnsigned;
else throw new NotSupportedException();
}
UnpackDelegate unpacker;
if (UnpackerMapping.TryGetValue(t, out unpacker))
return unpacker(this, reader);
if (t.IsArray)
{
if (!reader.Read() || (!reader.IsArray() && reader.Type != TypePrefixes.Nil))
throw new FormatException();
if (reader.Type == TypePrefixes.Nil)
return null;
Type et = t.GetElementType();
Array ary = Array.CreateInstance(et, (int)reader.Length);
for (int i = 0; i < ary.Length; i++)
ary.SetValue(Unpack(reader, et), i);
return ary;
}
if (!reader.Read())
throw new FormatException();
if (reader.Type == TypePrefixes.Nil)
return null;
if (t.IsInterface)
{
if (reader.Type != TypePrefixes.FixArray && reader.Length != 2)
throw new FormatException();
if (!reader.Read() || !reader.IsRaw())
throw new FormatException();
CheckBufferSize((int)reader.Length);
reader.ReadValueRaw(_buf, 0, (int)reader.Length);
t = Type.GetType(Encoding.UTF8.GetString(_buf, 0, (int)reader.Length));
if (!reader.Read() || reader.Type == TypePrefixes.Nil)
throw new FormatException();
}
if (!reader.IsMap())
throw new FormatException();
object o = FormatterServices.GetUninitializedObject(t);
ReflectionCacheEntry entry = ReflectionCache.Lookup(t);
int members = (int)reader.Length;
for (int i = 0; i < members; i++)
{
if (!reader.Read() || !reader.IsRaw())
throw new FormatException();
CheckBufferSize((int)reader.Length);
reader.ReadValueRaw(_buf, 0, (int)reader.Length);
string name = Encoding.UTF8.GetString(_buf, 0, (int)reader.Length);
FieldInfo f;
if (!entry.FieldMap.TryGetValue(name, out f))
throw new FormatException();
f.SetValue(o, Unpack(reader, f.FieldType));
}
IDeserializationCallback callback = o as IDeserializationCallback;
if (callback != null)
callback.OnDeserialization(this);
return o;
}
void CheckBufferSize(int size)
{
if (_buf.Length < size)
Array.Resize<byte>(ref _buf, size);
}
static void StringPacker(ObjectPacker packer, MsgPackWriter writer, object o)
{
writer.Write(Encoding.UTF8.GetBytes((string)o));
}
static object StringUnpacker(ObjectPacker packer, MsgPackReader reader)
{
if (!reader.Read())
throw new FormatException();
if (reader.Type == TypePrefixes.Nil)
return null;
if (!reader.IsRaw())
throw new FormatException();
packer.CheckBufferSize((int)reader.Length);
reader.ReadValueRaw(packer._buf, 0, (int)reader.Length);
return Encoding.UTF8.GetString(packer._buf, 0, (int)reader.Length);
}
}
}
namespace MsgPack
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.IO;
using System.Text;
public class MsgPackWriter
{
Stream _strm;
Encoding _encoding = Encoding.UTF8;
Encoder _encoder = Encoding.UTF8.GetEncoder();
byte[] _tmp = new byte[9];
byte[] _buf = new byte[64];
public MsgPackWriter(Stream strm)
{
_strm = strm;
}
public void Write(byte x)
{
if (x < 128)
{
_strm.WriteByte(x);
}
else
{
byte[] tmp = _tmp;
tmp[0] = 0xcc;
tmp[1] = x;
_strm.Write(tmp, 0, 2);
}
}
public void Write(ushort x)
{
if (x < 0x100)
{
Write((byte)x);
}
else
{
byte[] tmp = _tmp;
tmp[0] = 0xcd;
tmp[1] = (byte)(x >> 8);
tmp[2] = (byte)x;
_strm.Write(tmp, 0, 3);
}
}
public void Write(char x)
{
Write((ushort)x);
}
public void Write(uint x)
{
if (x < 0x10000)
{
Write((ushort)x);
}
else
{
byte[] tmp = _tmp;
tmp[0] = 0xce;
tmp[1] = (byte)(x >> 24);
tmp[2] = (byte)(x >> 16);
tmp[3] = (byte)(x >> 8);
tmp[4] = (byte)x;
_strm.Write(tmp, 0, 5);
}
}
public void Write(ulong x)
{
if (x < 0x100000000)
{
Write((uint)x);
}
else
{
byte[] tmp = _tmp;
tmp[0] = 0xcf;
tmp[1] = (byte)(x >> 56);
tmp[2] = (byte)(x >> 48);
tmp[3] = (byte)(x >> 40);
tmp[4] = (byte)(x >> 32);
tmp[5] = (byte)(x >> 24);
tmp[6] = (byte)(x >> 16);
tmp[7] = (byte)(x >> 8);
tmp[8] = (byte)x;
_strm.Write(tmp, 0, 9);
}
}
public void Write(sbyte x)
{
if (x >= -32 && x <= -1)
{
_strm.WriteByte((byte)(0xe0 | (byte)x));
}
else if (x >= 0 && x <= 127)
{
_strm.WriteByte((byte)x);
}
else
{
byte[] tmp = _tmp;
tmp[0] = 0xd0;
tmp[1] = (byte)x;
_strm.Write(tmp, 0, 2);
}
}
public void Write(short x)
{
if (x >= sbyte.MinValue && x <= sbyte.MaxValue)
{
Write((sbyte)x);
}
else
{
byte[] tmp = _tmp;
tmp[0] = 0xd1;
tmp[1] = (byte)(x >> 8);
tmp[2] = (byte)x;
_strm.Write(tmp, 0, 3);
}
}
public void Write(int x)
{
if (x >= short.MinValue && x <= short.MaxValue)
{
Write((short)x);
}
else
{
byte[] tmp = _tmp;
tmp[0] = 0xd2;
tmp[1] = (byte)(x >> 24);
tmp[2] = (byte)(x >> 16);
tmp[3] = (byte)(x >> 8);
tmp[4] = (byte)x;
_strm.Write(tmp, 0, 5);
}
}
public void Write(long x)
{
if (x >= int.MinValue && x <= int.MaxValue)
{
Write((int)x);
}
else
{
byte[] tmp = _tmp;
tmp[0] = 0xd3;
tmp[1] = (byte)(x >> 56);
tmp[2] = (byte)(x >> 48);
tmp[3] = (byte)(x >> 40);
tmp[4] = (byte)(x >> 32);
tmp[5] = (byte)(x >> 24);
tmp[6] = (byte)(x >> 16);
tmp[7] = (byte)(x >> 8);
tmp[8] = (byte)x;
_strm.Write(tmp, 0, 9);
}
}
public void WriteNil()
{
_strm.WriteByte(0xc0);
}
public void Write(bool x)
{
_strm.WriteByte((byte)(x ? 0xc3 : 0xc2));
}
public void Write(float x)
{
byte[] raw = BitConverter.GetBytes(x); // unsafeコードを使う?
byte[] tmp = _tmp;
tmp[0] = 0xca;
if (BitConverter.IsLittleEndian)
{
tmp[1] = raw[3];
tmp[2] = raw[2];
tmp[3] = raw[1];
tmp[4] = raw[0];
}
else
{
tmp[1] = raw[0];
tmp[2] = raw[1];
tmp[3] = raw[2];
tmp[4] = raw[3];
}
_strm.Write(tmp, 0, 5);
}
public void Write(double x)
{
byte[] raw = BitConverter.GetBytes(x); // unsafeコードを使う?
byte[] tmp = _tmp;
tmp[0] = 0xcb;
if (BitConverter.IsLittleEndian)
{
tmp[1] = raw[7];
tmp[2] = raw[6];
tmp[3] = raw[5];
tmp[4] = raw[4];
tmp[5] = raw[3];
tmp[6] = raw[2];
tmp[7] = raw[1];
tmp[8] = raw[0];
}
else
{
tmp[1] = raw[0];
tmp[2] = raw[1];
tmp[3] = raw[2];
tmp[4] = raw[3];
tmp[5] = raw[4];
tmp[6] = raw[5];
tmp[7] = raw[6];
tmp[8] = raw[7];
}
_strm.Write(tmp, 0, 9);
}
public void Write(byte[] bytes)
{
WriteRawHeader(bytes.Length);
_strm.Write(bytes, 0, bytes.Length);
}
public void WriteRawHeader(int N)
{
WriteLengthHeader(N, 32, 0xa0, 0xda, 0xdb);
}
public void WriteArrayHeader(int N)
{
WriteLengthHeader(N, 16, 0x90, 0xdc, 0xdd);
}
public void WriteMapHeader(int N)
{
WriteLengthHeader(N, 16, 0x80, 0xde, 0xdf);
}
void WriteLengthHeader(int N, int fix_length, byte fix_prefix, byte len16bit_prefix, byte len32bit_prefix)
{
if (N < fix_length)
{
_strm.WriteByte((byte)(fix_prefix | N));
}
else
{
byte[] tmp = _tmp;
int header_len;
if (N < 0x10000)
{
tmp[0] = len16bit_prefix;
tmp[1] = (byte)(N >> 8);
tmp[2] = (byte)N;
header_len = 3;
}
else
{
tmp[0] = len32bit_prefix;
tmp[1] = (byte)(N >> 24);
tmp[2] = (byte)(N >> 16);
tmp[3] = (byte)(N >> 8);
tmp[4] = (byte)N;
header_len = 5;
}
_strm.Write(tmp, 0, header_len);
}
}
public void Write(string x)
{
Write(x, false);
}
public void Write(string x, bool highProbAscii)
{
Write(x, _buf, highProbAscii);
}
public void Write(string x, byte[] buf)
{
Write(x, buf, false);
}
public unsafe void Write(string x, byte[] buf, bool highProbAscii)
{
Encoder encoder = _encoder;
fixed (char* pstr = x)
fixed (byte* pbuf = buf)
{
if (highProbAscii && x.Length <= buf.Length)
{
bool isAsciiFullCompatible = true;
for (int i = 0; i < x.Length; i++)
{
int v = (int)pstr[i];
if (v > 0x7f)
{
isAsciiFullCompatible = false;
break;
}
buf[i] = (byte)v;
}
if (isAsciiFullCompatible)
{
WriteRawHeader(x.Length);
_strm.Write(buf, 0, x.Length);
return;
}
}
WriteRawHeader(encoder.GetByteCount(pstr, x.Length, true));
int str_len = x.Length;
char* p = pstr;
int convertedChars, bytesUsed;
bool completed = true;
while (str_len > 0 || !completed)
{
encoder.Convert(p, str_len, pbuf, buf.Length, false, out convertedChars, out bytesUsed, out completed);
_strm.Write(buf, 0, bytesUsed);
str_len -= convertedChars;
p += convertedChars;
}
}
}
}
}
namespace MsgPack
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.IO;
using System.Text;
public class MsgPackReader
{
Stream _strm;
byte[] _tmp0 = new byte[8];
byte[] _tmp1 = new byte[8];
Encoding _encoding = Encoding.UTF8;
Decoder _decoder = Encoding.UTF8.GetDecoder();
byte[] _buf = new byte[64];
public MsgPackReader(Stream strm)
{
_strm = strm;
}
public TypePrefixes Type { get; private set; }
public bool ValueBoolean { get; private set; }
public uint Length { get; private set; }
public uint ValueUnsigned { get; private set; }
public ulong ValueUnsigned64 { get; private set; }
public int ValueSigned { get; private set; }
public long ValueSigned64 { get; private set; }
public float ValueFloat { get; private set; }
public double ValueDouble { get; private set; }
public bool IsSigned()
{
return this.Type == TypePrefixes.NegativeFixNum ||
this.Type == TypePrefixes.PositiveFixNum ||
this.Type == TypePrefixes.Int8 ||
this.Type == TypePrefixes.Int16 ||
this.Type == TypePrefixes.Int32;
}
public bool IsBoolean()
{
return this.Type == TypePrefixes.True || this.Type == TypePrefixes.False;
}
public bool IsSigned64()
{
return this.Type == TypePrefixes.Int64;
}
public bool IsUnsigned()
{
return this.Type == TypePrefixes.PositiveFixNum ||
this.Type == TypePrefixes.UInt8 ||
this.Type == TypePrefixes.UInt16 ||
this.Type == TypePrefixes.UInt32;
}
public bool IsUnsigned64()
{
return this.Type == TypePrefixes.UInt64;
}
public bool IsRaw()
{
return this.Type == TypePrefixes.FixRaw || this.Type == TypePrefixes.Raw16 || this.Type == TypePrefixes.Raw32;
}
public bool IsArray()
{
return this.Type == TypePrefixes.FixArray || this.Type == TypePrefixes.Array16 || this.Type == TypePrefixes.Array32;
}
public bool IsMap()
{
return this.Type == TypePrefixes.FixMap || this.Type == TypePrefixes.Map16 || this.Type == TypePrefixes.Map32;
}
public bool Read()
{
byte[] tmp0 = _tmp0, tmp1 = _tmp1;
int x = _strm.ReadByte();
if (x < 0)
return false; // EOS
if (x >= 0x00 && x <= 0x7f)
{
this.Type = TypePrefixes.PositiveFixNum;
}
else if (x >= 0xe0 && x <= 0xff)
{
this.Type = TypePrefixes.NegativeFixNum;
}
else if (x >= 0xa0 && x <= 0xbf)
{
this.Type = TypePrefixes.FixRaw;
}
else if (x >= 0x90 && x <= 0x9f)
{
this.Type = TypePrefixes.FixArray;
}
else if (x >= 0x80 && x <= 0x8f)
{
this.Type = TypePrefixes.FixMap;
}
else
{
this.Type = (TypePrefixes)x;
}
switch (this.Type)
{
case TypePrefixes.Nil:
break;
case TypePrefixes.False:
ValueBoolean = false;
break;
case TypePrefixes.True:
ValueBoolean = true;
break;
case TypePrefixes.Float:
_strm.Read(tmp0, 0, 4);
if (BitConverter.IsLittleEndian)
{
tmp1[0] = tmp0[3];
tmp1[1] = tmp0[2];
tmp1[2] = tmp0[1];
tmp1[3] = tmp0[0];
ValueFloat = BitConverter.ToSingle(tmp1, 0);
}
else
{
ValueFloat = BitConverter.ToSingle(tmp0, 0);
}
break;
case TypePrefixes.Double:
_strm.Read(tmp0, 0, 8);
if (BitConverter.IsLittleEndian)
{
tmp1[0] = tmp0[7];
tmp1[1] = tmp0[6];
tmp1[2] = tmp0[5];
tmp1[3] = tmp0[4];
tmp1[4] = tmp0[3];
tmp1[5] = tmp0[2];
tmp1[6] = tmp0[1];
tmp1[7] = tmp0[0];
ValueDouble = BitConverter.ToDouble(tmp1, 0);
}
else
{
ValueDouble = BitConverter.ToDouble(tmp0, 0);
}
break;
case TypePrefixes.NegativeFixNum:
ValueSigned = (x & 0x1f) - 0x20;
break;
case TypePrefixes.PositiveFixNum:
ValueSigned = x & 0x7f;
ValueUnsigned = (uint)ValueSigned;
break;
case TypePrefixes.UInt8:
x = _strm.ReadByte();
if (x < 0)
throw new FormatException();
ValueUnsigned = (uint)x;
break;
case TypePrefixes.UInt16:
if (_strm.Read(tmp0, 0, 2) != 2)
throw new FormatException();
ValueUnsigned = ((uint)tmp0[0] << 8) | (uint)tmp0[1];
break;
case TypePrefixes.UInt32:
if (_strm.Read(tmp0, 0, 4) != 4)
throw new FormatException();
ValueUnsigned = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3];
break;
case TypePrefixes.UInt64:
if (_strm.Read(tmp0, 0, 8) != 8)
throw new FormatException();
ValueUnsigned64 = ((ulong)tmp0[0] << 56) | ((ulong)tmp0[1] << 48) | ((ulong)tmp0[2] << 40) | ((ulong)tmp0[3] << 32) | ((ulong)tmp0[4] << 24) | ((ulong)tmp0[5] << 16) | ((ulong)tmp0[6] << 8) | (ulong)tmp0[7];
break;
case TypePrefixes.Int8:
x = _strm.ReadByte();
if (x < 0)
throw new FormatException();
ValueSigned = (sbyte)x;
break;
case TypePrefixes.Int16:
if (_strm.Read(tmp0, 0, 2) != 2)
throw new FormatException();
ValueSigned = (short)((tmp0[0] << 8) | tmp0[1]);
break;
case TypePrefixes.Int32:
if (_strm.Read(tmp0, 0, 4) != 4)
throw new FormatException();
ValueSigned = (tmp0[0] << 24) | (tmp0[1] << 16) | (tmp0[2] << 8) | tmp0[3];
break;
case TypePrefixes.Int64:
if (_strm.Read(tmp0, 0, 8) != 8)
throw new FormatException();
ValueSigned64 = ((long)tmp0[0] << 56) | ((long)tmp0[1] << 48) | ((long)tmp0[2] << 40) | ((long)tmp0[3] << 32) | ((long)tmp0[4] << 24) | ((long)tmp0[5] << 16) | ((long)tmp0[6] << 8) | (long)tmp0[7];
break;
case TypePrefixes.FixRaw:
Length = (uint)(x & 0x1f);
break;
case TypePrefixes.FixArray:
case TypePrefixes.FixMap:
Length = (uint)(x & 0xf);
break;
case TypePrefixes.Raw16:
case TypePrefixes.Array16:
case TypePrefixes.Map16:
if (_strm.Read(tmp0, 0, 2) != 2)
throw new FormatException();
Length = ((uint)tmp0[0] << 8) | (uint)tmp0[1];
break;
case TypePrefixes.Raw32:
case TypePrefixes.Array32:
case TypePrefixes.Map32:
if (_strm.Read(tmp0, 0, 4) != 4)
throw new FormatException();
Length = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3];
break;
default:
throw new FormatException();
}
return true;
}
public int ReadValueRaw(byte[] buf, int offset, int count)
{
return _strm.Read(buf, offset, count);
}
public string ReadRawString()
{
return ReadRawString(_buf);
}
public unsafe string ReadRawString(byte[] buf)
{
if (this.Length < buf.Length)
{
if (ReadValueRaw(buf, 0, (int)this.Length) != this.Length)
{
throw new FormatException();
}
return _encoding.GetString(buf, 0, (int)this.Length);
}
// Poor implementation
byte[] tmp = new byte[(int)this.Length];
if (ReadValueRaw(tmp, 0, tmp.Length) != tmp.Length)
throw new FormatException();
return _encoding.GetString(tmp);
}
}
}
namespace MsgPack
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using MsgPack.Compiler;
public class CompiledPacker
{
static PackerBase _publicFieldPacker, _allFieldPacker;
PackerBase _packer;
static CompiledPacker()
{
_publicFieldPacker = new MethodBuilderPacker();
_allFieldPacker = new DynamicMethodPacker();
}
public CompiledPacker() : this(false) { }
public CompiledPacker(bool packPrivateField)
{
_packer = (packPrivateField ? _allFieldPacker : _publicFieldPacker);
}
public void Prepare<T>()
{
_packer.CreatePacker<T>();
_packer.CreateUnpacker<T>();
}
#region Generics Pack/Unpack Methods
public byte[] Pack<T>(T o)
{
using (MemoryStream ms = new MemoryStream())
{
Pack<T>(ms, o);
return ms.ToArray();
}
}
public void Pack<T>(Stream strm, T o)
{
_packer.CreatePacker<T>()(new MsgPackWriter(strm), o);
}
public T Unpack<T>(byte[] buf)
{
return Unpack<T>(buf, 0, buf.Length);
}
public T Unpack<T>(byte[] buf, int offset, int size)
{
using (MemoryStream ms = new MemoryStream(buf, offset, size))
{
return Unpack<T>(ms);
}
}
public T Unpack<T>(Stream strm)
{
return _packer.CreateUnpacker<T>()(new MsgPackReader(strm));
}
#endregion
#region Non-generics Pack/Unpack Methods
public byte[] Pack(object o)
{
using (MemoryStream ms = new MemoryStream())
{
Pack(ms, o);
return ms.ToArray();
}
}
public void Pack(Stream strm, object o)
{
throw new NotImplementedException();
}
public object Unpack(Type t, byte[] buf)
{
return Unpack(t, buf, 0, buf.Length);
}
public object Unpack(Type t, byte[] buf, int offset, int size)
{
using (MemoryStream ms = new MemoryStream(buf, offset, size))
{
return Unpack(t, ms);
}
}
public object Unpack(Type t, Stream strm)
{
throw new NotImplementedException();
}
#endregion
#region Compiled Packer Implementations
public abstract class PackerBase
{
Dictionary<Type, Delegate> _packers = new Dictionary<Type, Delegate>();
Dictionary<Type, Delegate> _unpackers = new Dictionary<Type, Delegate>();
protected Dictionary<Type, MethodInfo> _packMethods = new Dictionary<Type, MethodInfo>();
protected Dictionary<Type, MethodInfo> _unpackMethods = new Dictionary<Type, MethodInfo>();
protected PackerBase()
{
DefaultPackMethods.Register(_packMethods, _unpackMethods);
}
public Action<MsgPackWriter, T> CreatePacker<T>()
{
Delegate d;
lock (_packers)
{
if (!_packers.TryGetValue(typeof(T), out d))
{
d = CreatePacker_Internal<T>();
_packers.Add(typeof(T), d);
}
}
return (Action<MsgPackWriter, T>)d;
}
public Func<MsgPackReader, T> CreateUnpacker<T>()
{
Delegate d;
lock (_unpackers)
{
if (!_unpackers.TryGetValue(typeof(T), out d))
{
d = CreateUnpacker_Internal<T>();
_unpackers.Add(typeof(T), d);
}
}
return (Func<MsgPackReader, T>)d;
}
protected abstract Action<MsgPackWriter, T> CreatePacker_Internal<T>();
protected abstract Func<MsgPackReader, T> CreateUnpacker_Internal<T>();
}
public sealed class DynamicMethodPacker : PackerBase
{
private static MethodInfo LookupMemberMappingMethod;
static Dictionary<Type, IDictionary<string, int>> UnpackMemberMappings;
static DynamicMethodPacker()
{
UnpackMemberMappings = new Dictionary<Type, IDictionary<string, int>>();
LookupMemberMappingMethod = typeof(DynamicMethodPacker).GetMethod("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic);
}
public DynamicMethodPacker()
: base()
{
}
protected override Action<MsgPackWriter, T> CreatePacker_Internal<T>()
{
DynamicMethod dm = CreatePacker(typeof(T), CreatePackDynamicMethod(typeof(T)));
return (Action<MsgPackWriter, T>)dm.CreateDelegate(typeof(Action<MsgPackWriter, T>));
}
protected override Func<MsgPackReader, T> CreateUnpacker_Internal<T>()
{
DynamicMethod dm = CreateUnpacker(typeof(T), CreateUnpackDynamicMethod(typeof(T)));
return (Func<MsgPackReader, T>)dm.CreateDelegate(typeof(Func<MsgPackReader, T>));
}
DynamicMethod CreatePacker(Type t, DynamicMethod dm)
{
ILGenerator il = dm.GetILGenerator();
_packMethods.Add(t, dm);
PackILGenerator.EmitPackCode(t, dm, il, LookupMembers, FormatMemberName, LookupPackMethod);
return dm;
}
DynamicMethod CreateUnpacker(Type t, DynamicMethod dm)
{
ILGenerator il = dm.GetILGenerator();
_unpackMethods.Add(t, dm);
PackILGenerator.EmitUnpackCode(t, dm, il, LookupMembers, FormatMemberName, LookupUnpackMethod,
LookupMemberMapping, LookupMemberMappingMethod);
return dm;
}
static DynamicMethod CreatePackDynamicMethod(Type t)
{
return CreateDynamicMethod(typeof(void), new Type[] { typeof(MsgPackWriter), t });
}
static DynamicMethod CreateUnpackDynamicMethod(Type t)
{
return CreateDynamicMethod(t, new Type[] { typeof(MsgPackReader) });
}
static MemberInfo[] LookupMembers(Type t)
{
BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
List<MemberInfo> list = new List<MemberInfo>();
list.AddRange(t.GetFields(baseFlags));
// TODO: Add NonSerialized Attribute Filter ?
return list.ToArray();
}
MethodInfo LookupPackMethod(Type t)
{
MethodInfo mi;
DynamicMethod dm;
if (_packMethods.TryGetValue(t, out mi))
return mi;
dm = CreatePackDynamicMethod(t);
return CreatePacker(t, dm);
}
MethodInfo LookupUnpackMethod(Type t)
{
MethodInfo mi;
if (_unpackMethods.TryGetValue(t, out mi))
return mi;
DynamicMethod dm = CreateUnpackDynamicMethod(t);
return CreateUnpacker(t, dm);
}
static string FormatMemberName(MemberInfo m)
{
if (m.MemberType != MemberTypes.Field)
return m.Name;
int pos;
string name = m.Name;
if (name[0] == '<' && (pos = name.IndexOf('>')) > 1)
name = name.Substring(1, pos - 1); // Auto-Property (\<.+\>) <ab>
return name;
}
static int _dynamicMethodIdx = 0;
static DynamicMethod CreateDynamicMethod(Type returnType, Type[] parameterTypes)
{
string name = "_" + Interlocked.Increment(ref _dynamicMethodIdx).ToString();
return new DynamicMethod(name, returnType, parameterTypes, true);
}
internal static IDictionary<string, int> LookupMemberMapping(Type t)
{
IDictionary<string, int> mapping;
lock (UnpackMemberMappings)
{
if (!UnpackMemberMappings.TryGetValue(t, out mapping))
{
mapping = new Dictionary<string, int>();
UnpackMemberMappings.Add(t, mapping);
}
}
return mapping;
}
}
public sealed class MethodBuilderPacker : PackerBase
{
public const string AssemblyName = "MessagePackInternalAssembly";
static AssemblyName DynamicAsmName;
static AssemblyBuilder DynamicAsmBuilder;
static ModuleBuilder DynamicModuleBuilder;
private static MethodInfo LookupMemberMappingMethod;
static Dictionary<Type, IDictionary<string, int>> UnpackMemberMappings;
static MethodBuilderPacker()
{
UnpackMemberMappings = new Dictionary<Type, IDictionary<string, int>>();
LookupMemberMappingMethod = typeof(MethodBuilderPacker).GetMethod("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic);
DynamicAsmName = new AssemblyName(AssemblyName);
DynamicAsmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(DynamicAsmName, AssemblyBuilderAccess.Run);
DynamicModuleBuilder = DynamicAsmBuilder.DefineDynamicModule(DynamicAsmName.Name);
}
public MethodBuilderPacker()
: base()
{
}
protected override Action<MsgPackWriter, T> CreatePacker_Internal<T>()
{
TypeBuilder tb;
MethodBuilder mb;
CreatePackMethodBuilder(typeof(T), out tb, out mb);
_packMethods.Add(typeof(T), mb);
CreatePacker(typeof(T), mb);
MethodInfo mi = ToCallableMethodInfo(typeof(T), tb, true);
return (Action<MsgPackWriter, T>)Delegate.CreateDelegate(typeof(Action<MsgPackWriter, T>), mi);
}
protected override Func<MsgPackReader, T> CreateUnpacker_Internal<T>()
{
TypeBuilder tb;
MethodBuilder mb;
CreateUnpackMethodBuilder(typeof(T), out tb, out mb);
_unpackMethods.Add(typeof(T), mb);
CreateUnpacker(typeof(T), mb);
MethodInfo mi = ToCallableMethodInfo(typeof(T), tb, false);
return (Func<MsgPackReader, T>)Delegate.CreateDelegate(typeof(Func<MsgPackReader, T>), mi);
}
void CreatePacker(Type t, MethodBuilder mb)
{
ILGenerator il = mb.GetILGenerator();
PackILGenerator.EmitPackCode(t, mb, il, LookupMembers, FormatMemberName, LookupPackMethod);
}
void CreateUnpacker(Type t, MethodBuilder mb)
{
ILGenerator il = mb.GetILGenerator();
PackILGenerator.EmitUnpackCode(t, mb, il, LookupMembers, FormatMemberName, LookupUnpackMethod,
LookupMemberMapping, LookupMemberMappingMethod);
}
MethodInfo ToCallableMethodInfo(Type t, TypeBuilder tb, bool isPacker)
{
Type type = tb.CreateType();
MethodInfo mi = type.GetMethod(isPacker ? "Pack" : "Unpack", BindingFlags.Static | BindingFlags.Public);
if (isPacker)
{
_packMethods[t] = mi;
}
else
{
_unpackMethods[t] = mi;
}
return mi;
}
MethodInfo LookupPackMethod(Type t)
{
MethodInfo mi;
TypeBuilder tb;
MethodBuilder mb;
if (_packMethods.TryGetValue(t, out mi))
return mi;
CreatePackMethodBuilder(t, out tb, out mb);
_packMethods.Add(t, mb);
CreatePacker(t, mb);
return ToCallableMethodInfo(t, tb, true);
}
MethodInfo LookupUnpackMethod(Type t)
{
MethodInfo mi;
TypeBuilder tb;
MethodBuilder mb;
if (_unpackMethods.TryGetValue(t, out mi))
return mi;
CreateUnpackMethodBuilder(t, out tb, out mb);
_unpackMethods.Add(t, mb);
CreateUnpacker(t, mb);
return ToCallableMethodInfo(t, tb, false);
}
static string FormatMemberName(MemberInfo m)
{
return m.Name;
}
static MemberInfo[] LookupMembers(Type t)
{
BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public;
List<MemberInfo> list = new List<MemberInfo>();
list.AddRange(t.GetFields(baseFlags));
// TODO: Add NonSerialized Attribute Filter ?
return list.ToArray();
}
static void CreatePackMethodBuilder(Type t, out TypeBuilder tb, out MethodBuilder mb)
{
tb = DynamicModuleBuilder.DefineType(t.Name + "PackerType", TypeAttributes.Public);
mb = tb.DefineMethod("Pack", MethodAttributes.Static | MethodAttributes.Public, typeof(void), new Type[] { typeof(MsgPackWriter), t });
}
static void CreateUnpackMethodBuilder(Type t, out TypeBuilder tb, out MethodBuilder mb)
{
tb = DynamicModuleBuilder.DefineType(t.Name + "UnpackerType", TypeAttributes.Public);
mb = tb.DefineMethod("Unpack", MethodAttributes.Static | MethodAttributes.Public, t, new Type[] { typeof(MsgPackReader) });
}
internal static IDictionary<string, int> LookupMemberMapping(Type t)
{
IDictionary<string, int> mapping;
lock (UnpackMemberMappings)
{
if (!UnpackMemberMappings.TryGetValue(t, out mapping))
{
mapping = new Dictionary<string, int>();
UnpackMemberMappings.Add(t, mapping);
}
}
return mapping;
}
}
#endregion
#region default pack/unpack methods
internal static class DefaultPackMethods
{
public static void Register(Dictionary<Type, MethodInfo> packMethods, Dictionary<Type, MethodInfo> unpackMethods)
{
RegisterPackMethods(packMethods);
RegisterUnpackMethods(unpackMethods);
}
#region Pack
static void RegisterPackMethods(Dictionary<Type, MethodInfo> packMethods)
{
Type type = typeof(DefaultPackMethods);
MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
string methodName = "Pack";
for (int i = 0; i < methods.Length; i++)
{
if (!methodName.Equals(methods[i].Name))
{
continue;
}
ParameterInfo[] parameters = methods[i].GetParameters();
if (parameters.Length != 2 || parameters[0].ParameterType != typeof(MsgPackWriter))
{
continue;
}
packMethods.Add(parameters[1].ParameterType, methods[i]);
}
}
internal static void Pack(MsgPackWriter writer, string x)
{
if (x == null)
{
writer.WriteNil();
}
else
{
writer.Write(x, false);
}
}
#endregion
#region Unpack
static void RegisterUnpackMethods(Dictionary<Type, MethodInfo> unpackMethods)
{
BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;
Type type = typeof(DefaultPackMethods);
MethodInfo mi = type.GetMethod("Unpack_Signed", flags);
unpackMethods.Add(typeof(sbyte), mi);
unpackMethods.Add(typeof(short), mi);
unpackMethods.Add(typeof(int), mi);
mi = type.GetMethod("Unpack_Signed64", flags);
unpackMethods.Add(typeof(long), mi);
mi = type.GetMethod("Unpack_Unsigned", flags);
unpackMethods.Add(typeof(byte), mi);
unpackMethods.Add(typeof(ushort), mi);
unpackMethods.Add(typeof(char), mi);
unpackMethods.Add(typeof(uint), mi);
mi = type.GetMethod("Unpack_Unsigned64", flags);
unpackMethods.Add(typeof(ulong), mi);
mi = type.GetMethod("Unpack_Boolean", flags);
unpackMethods.Add(typeof(bool), mi);
mi = type.GetMethod("Unpack_Float", flags);
unpackMethods.Add(typeof(float), mi);
mi = type.GetMethod("Unpack_Double", flags);
unpackMethods.Add(typeof(double), mi);
mi = type.GetMethod("Unpack_String", flags);
unpackMethods.Add(typeof(string), mi);
}
internal static int Unpack_Signed(MsgPackReader reader)
{
if (!reader.Read() || !reader.IsSigned())
UnpackFailed();
return reader.ValueSigned;
}
internal static long Unpack_Signed64(MsgPackReader reader)
{
if (!reader.Read())
{
UnpackFailed();
}
if (reader.IsSigned())
{
return reader.ValueSigned;
}
if (reader.IsSigned64())
{
return reader.ValueSigned64;
}
UnpackFailed();
return 0; // unused
}
internal static uint Unpack_Unsigned(MsgPackReader reader)
{
if (!reader.Read() || !reader.IsUnsigned())
UnpackFailed();
return reader.ValueUnsigned;
}
internal static ulong Unpack_Unsigned64(MsgPackReader reader)
{
if (!reader.Read())
UnpackFailed();
if (reader.IsUnsigned())
return reader.ValueUnsigned;
if (reader.IsUnsigned64())
return reader.ValueUnsigned64;
UnpackFailed();
return 0; // unused
}
internal static bool Unpack_Boolean(MsgPackReader reader)
{
if (!reader.Read() || !reader.IsBoolean())
UnpackFailed();
return reader.ValueBoolean;
}
internal static float Unpack_Float(MsgPackReader reader)
{
if (!reader.Read() || reader.Type != TypePrefixes.Float)
UnpackFailed();
return reader.ValueFloat;
}
internal static double Unpack_Double(MsgPackReader reader)
{
if (!reader.Read() || reader.Type != TypePrefixes.Double)
UnpackFailed();
return reader.ValueDouble;
}
internal static string Unpack_String(MsgPackReader reader)
{
if (!reader.Read() || !reader.IsRaw())
UnpackFailed();
return reader.ReadRawString();
}
internal static void UnpackFailed()
{
throw new FormatException();
}
#endregion
}
#endregion
}
}
namespace MsgPack
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
public class BoxingPacker
{
static Type KeyValuePairDefinitionType;
static BoxingPacker()
{
KeyValuePairDefinitionType = typeof(KeyValuePair<object, object>).GetGenericTypeDefinition();
}
public void Pack(Stream strm, object o)
{
MsgPackWriter writer = new MsgPackWriter(strm);
Pack(writer, o);
}
public byte[] Pack(object o)
{
using (MemoryStream ms = new MemoryStream())
{
Pack(ms, o);
return ms.ToArray();
}
}
void Pack(MsgPackWriter writer, object o)
{
if (o == null)
{
writer.WriteNil();
return;
}
Type t = o.GetType();
if (t.IsPrimitive)
{
if (t.Equals(typeof(int))) writer.Write((int)o);
else if (t.Equals(typeof(uint))) writer.Write((uint)o);
else if (t.Equals(typeof(float))) writer.Write((float)o);
else if (t.Equals(typeof(double))) writer.Write((double)o);
else if (t.Equals(typeof(long))) writer.Write((long)o);
else if (t.Equals(typeof(ulong))) writer.Write((ulong)o);
else if (t.Equals(typeof(bool))) writer.Write((bool)o);
else if (t.Equals(typeof(byte))) writer.Write((byte)o);
else if (t.Equals(typeof(sbyte))) writer.Write((sbyte)o);
else if (t.Equals(typeof(short))) writer.Write((short)o);
else if (t.Equals(typeof(ushort))) writer.Write((ushort)o);
else throw new NotSupportedException(); // char?
return;
}
IDictionary dic = o as IDictionary;
if (dic != null)
{
writer.WriteMapHeader(dic.Count);
foreach (System.Collections.DictionaryEntry e in dic)
{
Pack(writer, e.Key);
Pack(writer, e.Value);
}
return;
}
if (t.IsArray)
{
Array ary = (Array)o;
Type et = t.GetElementType();
// KeyValuePair<K,V>[] (Map Type)
if (et.IsGenericType && et.GetGenericTypeDefinition().Equals(KeyValuePairDefinitionType))
{
PropertyInfo propKey = et.GetProperty("Key");
PropertyInfo propValue = et.GetProperty("Value");
writer.WriteMapHeader(ary.Length);
for (int i = 0; i < ary.Length; i++)
{
object e = ary.GetValue(i);
Pack(writer, propKey.GetValue(e, null));
Pack(writer, propValue.GetValue(e, null));
}
return;
}
// Array
writer.WriteArrayHeader(ary.Length);
for (int i = 0; i < ary.Length; i++)
Pack(writer, ary.GetValue(i));
return;
}
}
public object Unpack(Stream strm)
{
MsgPackReader reader = new MsgPackReader(strm);
return Unpack(reader);
}
public object Unpack(byte[] buf, int offset, int size)
{
using (MemoryStream ms = new MemoryStream(buf, offset, size))
{
return Unpack(ms);
}
}
public object Unpack(byte[] buf)
{
return Unpack(buf, 0, buf.Length);
}
object Unpack(MsgPackReader reader)
{
if (!reader.Read())
{
throw new FormatException();
}
switch (reader.Type)
{
case TypePrefixes.PositiveFixNum:
case TypePrefixes.NegativeFixNum:
case TypePrefixes.Int8:
case TypePrefixes.Int16:
case TypePrefixes.Int32:
return reader.ValueSigned;
case TypePrefixes.Int64:
return reader.ValueSigned64;
case TypePrefixes.UInt8:
case TypePrefixes.UInt16:
case TypePrefixes.UInt32:
return reader.ValueUnsigned;
case TypePrefixes.UInt64:
return reader.ValueUnsigned64;
case TypePrefixes.True:
return true;
case TypePrefixes.False:
return false;
case TypePrefixes.Float:
return reader.ValueFloat;
case TypePrefixes.Double:
return reader.ValueDouble;
case TypePrefixes.Nil:
return null;
case TypePrefixes.FixRaw:
case TypePrefixes.Raw16:
case TypePrefixes.Raw32:
byte[] raw = new byte[reader.Length];
reader.ReadValueRaw(raw, 0, raw.Length);
return raw;
case TypePrefixes.FixArray:
case TypePrefixes.Array16:
case TypePrefixes.Array32:
object[] ary = new object[reader.Length];
for (int i = 0; i < ary.Length; i++)
ary[i] = Unpack(reader);
return ary;
case TypePrefixes.FixMap:
case TypePrefixes.Map16:
case TypePrefixes.Map32:
IDictionary<object, object> dic = new Dictionary<object, object>((int)reader.Length);
int count = (int)reader.Length;
for (int i = 0; i < count; i++)
{
object k = Unpack(reader);
object v = Unpack(reader);
dic.Add(k, v);
}
return dic;
default:
throw new FormatException();
}
}
}
}
namespace MsgPack.Compiler
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
public enum VariableType
{
Local,
Arg
}
}
namespace MsgPack.Compiler
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System.Reflection.Emit;
public class Variable
{
Variable(VariableType type, int index)
{
this.VarType = type;
this.Index = index;
}
public static Variable CreateLocal(LocalBuilder local)
{
return new Variable(VariableType.Local, local.LocalIndex);
}
public static Variable CreateArg(int idx)
{
return new Variable(VariableType.Arg, idx);
}
public VariableType VarType { get; set; }
public int Index { get; set; }
}
}
namespace MsgPack.Compiler
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Serialization;
static class PackILGenerator
{
#region Pack IL Generator
public static void EmitPackCode
(
Type type
, MethodInfo mi
, ILGenerator il
, Func<Type, MemberInfo[]> targetMemberSelector
, Func<MemberInfo, string> memberNameFormatter
, Func<Type, MethodInfo> lookupPackMethod
)
{
if (type.IsPrimitive || type.IsInterface)
{
throw new NotSupportedException();
}
Variable arg_writer = Variable.CreateArg(0);
Variable arg_obj = Variable.CreateArg(1);
Variable local_i = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
if (!type.IsValueType)
{
// null check
Label notNullLabel = il.DefineLabel();
il.EmitLd(arg_obj);
il.Emit(OpCodes.Brtrue_S, notNullLabel);
il.EmitLd(arg_writer);
il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("WriteNil", new Type[0]));
il.Emit(OpCodes.Ret);
il.MarkLabel(notNullLabel);
}
if (type.IsArray)
{
EmitPackArrayCode(mi, il, type, arg_writer, arg_obj, local_i, lookupPackMethod);
goto FinallyProcess;
}
// MsgPackWriter.WriteMapHeader
MemberInfo[] members = targetMemberSelector(type);
il.EmitLd(arg_writer);
il.EmitLdc(members.Length);
il.Emit(OpCodes.Callvirt, typeof(MsgPackWriter).GetMethod("WriteMapHeader", new Type[] { typeof(int) }));
for (int i = 0; i < members.Length; i++)
{
MemberInfo m = members[i];
Type mt = m.GetMemberType();
// write field-name
il.EmitLd(arg_writer);
il.EmitLdstr(memberNameFormatter(m));
il.EmitLd_True();
il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("Write", new Type[] { typeof(string), typeof(bool) }));
// write value
EmitPackMemberValueCode(mt, il, arg_writer, arg_obj, m, null, type, mi, lookupPackMethod);
}
FinallyProcess:
il.Emit(OpCodes.Ret);
}
static void EmitPackArrayCode
(
MethodInfo mi
, ILGenerator il
, Type t
, Variable var_writer
, Variable var_obj
, Variable var_loop
, Func<Type, MethodInfo> lookupPackMethod
)
{
Type et = t.GetElementType();
il.EmitLd(var_writer, var_obj);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("WriteArrayHeader", new Type[] { typeof(int) }));
Label beginLabel = il.DefineLabel();
Label exprLabel = il.DefineLabel();
// for-loop: init loop counter
il.EmitLdc(0);
il.EmitSt(var_loop);
// jump
il.Emit(OpCodes.Br_S, exprLabel);
// mark begin-label
il.MarkLabel(beginLabel);
// write element
EmitPackMemberValueCode(et, il, var_writer, var_obj, null, var_loop, t, mi, lookupPackMethod);
// increment loop-counter
il.EmitLd(var_loop);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.EmitSt(var_loop);
// mark expression label
il.MarkLabel(exprLabel);
// expression
il.EmitLd(var_loop, var_obj);
il.Emit(OpCodes.Ldlen);
il.Emit(OpCodes.Blt_S, beginLabel);
}
/// <param name="m">(optional)</param>
/// <param name="elementIdx">(optional)</param>
static void EmitPackMemberValueCode(Type type, ILGenerator il, Variable var_writer, Variable var_obj,
MemberInfo m, Variable elementIdx, Type currentType, MethodInfo currentMethod, Func<Type, MethodInfo> lookupPackMethod)
{
MethodInfo mi;
il.EmitLd(var_writer, var_obj);
if (m != null)
il.EmitLdMember(m);
if (elementIdx != null)
{
il.EmitLd(elementIdx);
il.Emit(OpCodes.Ldelem, type);
}
if (type.IsPrimitive)
{
mi = typeof(MsgPackWriter).GetMethod("Write", new Type[] { type });
}
else
{
if (currentType == type)
{
mi = currentMethod;
}
else
{
mi = lookupPackMethod(type);
}
}
il.Emit(OpCodes.Call, mi);
}
#endregion
#region Unpack IL Generator
public static void EmitUnpackCode(Type type, MethodInfo mi, ILGenerator il,
Func<Type, MemberInfo[]> targetMemberSelector,
Func<MemberInfo, string> memberNameFormatter,
Func<Type, MethodInfo> lookupUnpackMethod,
Func<Type, IDictionary<string, int>> lookupMemberMapping,
MethodInfo lookupMemberMappingMethod)
{
if (type.IsArray)
{
EmitUnpackArrayCode(type, mi, il, targetMemberSelector, memberNameFormatter, lookupUnpackMethod);
}
else
{
EmitUnpackMapCode(type, mi, il, targetMemberSelector, memberNameFormatter, lookupUnpackMethod, lookupMemberMapping, lookupMemberMappingMethod);
}
}
static void EmitUnpackMapCode(Type type, MethodInfo mi, ILGenerator il,
Func<Type, MemberInfo[]> targetMemberSelector,
Func<MemberInfo, string> memberNameFormatter,
Func<Type, MethodInfo> lookupUnpackMethod,
Func<Type, IDictionary<string, int>> lookupMemberMapping,
MethodInfo lookupMemberMappingMethod)
{
MethodInfo failedMethod = typeof(PackILGenerator).GetMethod("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic);
MemberInfo[] members = targetMemberSelector(type);
IDictionary<string, int> member_mapping = lookupMemberMapping(type);
for (int i = 0; i < members.Length; i++)
member_mapping.Add(memberNameFormatter(members[i]), i);
Variable msgpackReader = Variable.CreateArg(0);
Variable obj = Variable.CreateLocal(il.DeclareLocal(type));
Variable num_of_fields = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
Variable loop_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
Variable mapping = Variable.CreateLocal(il.DeclareLocal(typeof(IDictionary<string, int>)));
Variable switch_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
Variable var_type = Variable.CreateLocal(il.DeclareLocal(typeof(Type)));
// if (!MsgPackReader.Read()) UnpackFailed ();
// if (MsgPackReader.Type == TypePrefixes.Nil) return null;
// if (!MsgPackReader.IsMap ()) UnpackFailed ();
EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsMap"), failedMethod, true);
// type = typeof (T)
il.Emit(OpCodes.Ldtoken, type);
il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
il.EmitSt(var_type);
// mapping = LookupMemberMapping (typeof (T))
il.EmitLd(var_type);
il.Emit(OpCodes.Call, lookupMemberMappingMethod);
il.EmitSt(mapping);
// object o = FormatterServices.GetUninitializedObject (Type);
il.EmitLd(var_type);
il.Emit(OpCodes.Call, typeof(FormatterServices).GetMethod("GetUninitializedObject"));
il.Emit(OpCodes.Castclass, type);
il.EmitSt(obj);
// num_of_fields = (int)reader.Length
il.EmitLd(msgpackReader);
il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Length").GetGetMethod());
il.EmitSt(num_of_fields);
// Loop labels
Label lblLoopStart = il.DefineLabel();
Label lblLoopExpr = il.DefineLabel();
// i = 0;
il.EmitLdc(0);
il.EmitSt(loop_idx);
il.Emit(OpCodes.Br, lblLoopExpr);
il.MarkLabel(lblLoopStart);
/* process */
// if (!MsgPackReader.Read() || !MsgPackReader.IsRaw()) UnpackFailed();
EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsRaw"), failedMethod, false);
// MsgPackReader.ReadRawString ()
// if (!Dictionary.TryGetValue (,)) UnpackFailed();
Label lbl3 = il.DefineLabel();
il.EmitLd(mapping);
il.EmitLd(msgpackReader);
il.Emit(OpCodes.Call, typeof(MsgPackReader).GetMethod("ReadRawString", new Type[0]));
il.Emit(OpCodes.Ldloca_S, (byte)switch_idx.Index);
il.Emit(OpCodes.Callvirt, typeof(IDictionary<string, int>).GetMethod("TryGetValue"));
il.Emit(OpCodes.Brtrue, lbl3);
il.Emit(OpCodes.Call, failedMethod);
il.MarkLabel(lbl3);
// switch
Label[] switchCases = new Label[members.Length];
for (int i = 0; i < switchCases.Length; i++)
switchCases[i] = il.DefineLabel();
Label switchCaseEndLabel = il.DefineLabel();
il.EmitLd(switch_idx);
il.Emit(OpCodes.Switch, switchCases);
il.Emit(OpCodes.Call, failedMethod);
for (int i = 0; i < switchCases.Length; i++)
{
il.MarkLabel(switchCases[i]);
MemberInfo minfo = members[i];
Type mt = minfo.GetMemberType();
MethodInfo unpack_method = lookupUnpackMethod(mt);
il.EmitLd(obj);
il.EmitLd(msgpackReader);
il.Emit(OpCodes.Call, unpack_method);
il.EmitStMember(minfo);
il.Emit(OpCodes.Br, switchCaseEndLabel);
}
il.MarkLabel(switchCaseEndLabel);
// i ++
il.EmitLd(loop_idx);
il.EmitLdc(1);
il.Emit(OpCodes.Add);
il.EmitSt(loop_idx);
// i < num_of_fields;
il.MarkLabel(lblLoopExpr);
il.EmitLd(loop_idx);
il.EmitLd(num_of_fields);
il.Emit(OpCodes.Blt, lblLoopStart);
// return
il.EmitLd(obj);
il.Emit(OpCodes.Ret);
}
static void EmitUnpackArrayCode(Type arrayType, MethodInfo mi, ILGenerator il,
Func<Type, MemberInfo[]> targetMemberSelector,
Func<MemberInfo, string> memberNameFormatter,
Func<Type, MethodInfo> lookupUnpackMethod)
{
Type elementType = arrayType.GetElementType();
MethodInfo failedMethod = typeof(PackILGenerator).GetMethod("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic);
Variable msgpackReader = Variable.CreateArg(0);
Variable obj = Variable.CreateLocal(il.DeclareLocal(arrayType));
Variable num_of_elements = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
Variable loop_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
Variable type = Variable.CreateLocal(il.DeclareLocal(typeof(Type)));
// if (!MsgPackReader.Read() || !MsgPackReader.IsArray ()) UnpackFailed ();
EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsArray"), failedMethod, true);
// type = typeof (T)
il.Emit(OpCodes.Ldtoken, elementType);
il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
il.EmitSt(type);
// num_of_elements = (int)reader.Length
il.EmitLd(msgpackReader);
il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Length").GetGetMethod());
il.EmitSt(num_of_elements);
// object o = Array.CreateInstance (Type, Length);
il.EmitLd(type);
il.EmitLd(num_of_elements);
il.Emit(OpCodes.Call, typeof(Array).GetMethod("CreateInstance", new Type[] { typeof(Type), typeof(int) }));
il.Emit(OpCodes.Castclass, arrayType);
il.EmitSt(obj);
// Unpack element method
MethodInfo unpack_method = lookupUnpackMethod(elementType);
// Loop labels
Label lblLoopStart = il.DefineLabel();
Label lblLoopExpr = il.DefineLabel();
// i = 0;
il.EmitLdc(0);
il.EmitSt(loop_idx);
il.Emit(OpCodes.Br, lblLoopExpr);
il.MarkLabel(lblLoopStart);
/* process */
il.EmitLd(obj, loop_idx);
il.EmitLd(msgpackReader);
il.Emit(OpCodes.Call, unpack_method);
il.Emit(OpCodes.Stelem, elementType);
// i ++
il.EmitLd(loop_idx);
il.EmitLdc(1);
il.Emit(OpCodes.Add);
il.EmitSt(loop_idx);
// i < num_of_fields;
il.MarkLabel(lblLoopExpr);
il.EmitLd(loop_idx);
il.EmitLd(num_of_elements);
il.Emit(OpCodes.Blt, lblLoopStart);
// return
il.EmitLd(obj);
il.Emit(OpCodes.Ret);
}
static void EmitUnpackReadAndTypeCheckCode(ILGenerator il, Variable msgpackReader, MethodInfo typeCheckMethod, MethodInfo failedMethod, bool nullCheckAndReturn)
{
Label lblFailed = il.DefineLabel();
Label lblNullReturn = nullCheckAndReturn ? il.DefineLabel() : default(Label);
Label lblPassed = il.DefineLabel();
il.EmitLd(msgpackReader);
il.Emit(OpCodes.Call, typeof(MsgPackReader).GetMethod("Read"));
il.Emit(OpCodes.Brfalse_S, lblFailed);
if (nullCheckAndReturn)
{
il.EmitLd(msgpackReader);
il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Type").GetGetMethod());
il.EmitLdc((int)TypePrefixes.Nil);
il.Emit(OpCodes.Beq_S, lblNullReturn);
}
il.EmitLd(msgpackReader);
il.Emit(OpCodes.Call, typeCheckMethod);
il.Emit(OpCodes.Brtrue_S, lblPassed);
il.Emit(OpCodes.Br, lblFailed);
if (nullCheckAndReturn)
{
il.MarkLabel(lblNullReturn);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ret);
}
il.MarkLabel(lblFailed);
il.Emit(OpCodes.Call, failedMethod);
il.MarkLabel(lblPassed);
}
/// <summary>Exception Helper</summary>
internal static void UnpackFailed()
{
throw new FormatException();
}
#endregion
#region Misc
static Type GetMemberType(this MemberInfo mi)
{
if (mi.MemberType == MemberTypes.Field)
return ((FieldInfo)mi).FieldType;
if (mi.MemberType == MemberTypes.Property)
return ((PropertyInfo)mi).PropertyType;
throw new ArgumentException();
}
#endregion
}
}
namespace MsgPack.Compiler
{
//
// Copyright 2011 Kazuki Oikawa
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Reflection;
using System.Reflection.Emit;
public static class EmitExtensions
{
public static void EmitLd(this ILGenerator il, Variable v)
{
switch (v.VarType)
{
case VariableType.Arg:
EmitLdarg(il, v);
break;
case VariableType.Local:
EmitLdloc(il, v);
break;
default:
throw new ArgumentException();
}
}
public static void EmitLd(this ILGenerator il, params Variable[] list)
{
for (int i = 0; i < list.Length; i++)
EmitLd(il, list[i]);
}
public static void EmitLdarg(this ILGenerator il, Variable v)
{
if (v.VarType != VariableType.Arg)
throw new ArgumentException();
switch (v.Index)
{
case 0: il.Emit(OpCodes.Ldarg_0); return;
case 1: il.Emit(OpCodes.Ldarg_1); return;
case 2: il.Emit(OpCodes.Ldarg_2); return;
case 3: il.Emit(OpCodes.Ldarg_3); return;
}
if (v.Index <= byte.MaxValue)
{
il.Emit(OpCodes.Ldarg_S, (byte)v.Index);
}
else if (v.Index <= short.MaxValue)
{
il.Emit(OpCodes.Ldarg, v.Index);
}
else
{
throw new FormatException();
}
}
public static void EmitLdloc(this ILGenerator il, Variable v)
{
if (v.VarType != VariableType.Local)
throw new ArgumentException();
switch (v.Index)
{
case 0: il.Emit(OpCodes.Ldloc_0); return;
case 1: il.Emit(OpCodes.Ldloc_1); return;
case 2: il.Emit(OpCodes.Ldloc_2); return;
case 3: il.Emit(OpCodes.Ldloc_3); return;
}
if (v.Index <= byte.MaxValue)
{
il.Emit(OpCodes.Ldloc_S, (byte)v.Index);
}
else if (v.Index <= short.MaxValue)
{
il.Emit(OpCodes.Ldloc, v.Index);
}
else
{
throw new FormatException();
}
}
public static void EmitSt(this ILGenerator il, Variable v)
{
switch (v.VarType)
{
case VariableType.Arg:
EmitStarg(il, v);
break;
case VariableType.Local:
EmitStloc(il, v);
break;
default:
throw new ArgumentException();
}
}
public static void EmitStarg(this ILGenerator il, Variable v)
{
if (v.VarType != VariableType.Arg)
throw new ArgumentException();
if (v.Index <= byte.MaxValue)
{
il.Emit(OpCodes.Starg_S, (byte)v.Index);
}
else if (v.Index <= short.MaxValue)
{
il.Emit(OpCodes.Starg, v.Index);
}
else
{
throw new FormatException();
}
}
public static void EmitStloc(this ILGenerator il, Variable v)
{
if (v.VarType != VariableType.Local)
throw new ArgumentException();
switch (v.Index)
{
case 0: il.Emit(OpCodes.Stloc_0); return;
case 1: il.Emit(OpCodes.Stloc_1); return;
case 2: il.Emit(OpCodes.Stloc_2); return;
case 3: il.Emit(OpCodes.Stloc_3); return;
}
if (v.Index <= byte.MaxValue)
{
il.Emit(OpCodes.Stloc_S, (byte)v.Index);
}
else if (v.Index <= short.MaxValue)
{
il.Emit(OpCodes.Stloc, v.Index);
}
else
{
throw new FormatException();
}
}
public static void EmitLdc(this ILGenerator il, int v)
{
switch (v)
{
case 0: il.Emit(OpCodes.Ldc_I4_0); return;
case 1: il.Emit(OpCodes.Ldc_I4_1); return;
case 2: il.Emit(OpCodes.Ldc_I4_2); return;
case 3: il.Emit(OpCodes.Ldc_I4_3); return;
case 4: il.Emit(OpCodes.Ldc_I4_4); return;
case 5: il.Emit(OpCodes.Ldc_I4_5); return;
case 6: il.Emit(OpCodes.Ldc_I4_6); return;
case 7: il.Emit(OpCodes.Ldc_I4_7); return;
case 8: il.Emit(OpCodes.Ldc_I4_8); return;
case -1: il.Emit(OpCodes.Ldc_I4_M1); return;
}
if (v <= sbyte.MaxValue && v >= sbyte.MinValue)
{
il.Emit(OpCodes.Ldc_I4_S, (sbyte)v);
}
else
{
il.Emit(OpCodes.Ldc_I4, v);
}
}
public static void EmitLd_False(this ILGenerator il)
{
il.Emit(OpCodes.Ldc_I4_1);
}
public static void EmitLd_True(this ILGenerator il)
{
il.Emit(OpCodes.Ldc_I4_1);
}
public static void EmitLdstr(this ILGenerator il, string v)
{
il.Emit(OpCodes.Ldstr, v);
}
public static void EmitLdMember(this ILGenerator il, MemberInfo m)
{
if (m.MemberType == MemberTypes.Field)
{
il.Emit(OpCodes.Ldfld, (FieldInfo)m);
}
else if (m.MemberType == MemberTypes.Property)
{
il.Emit(OpCodes.Callvirt, ((PropertyInfo)m).GetGetMethod(true));
}
else
{
throw new ArgumentException();
}
}
public static void EmitStMember(this ILGenerator il, MemberInfo m)
{
if (m.MemberType == MemberTypes.Field)
{
il.Emit(OpCodes.Stfld, (FieldInfo)m);
}
else if (m.MemberType == MemberTypes.Property)
{
il.Emit(OpCodes.Callvirt, ((PropertyInfo)m).GetSetMethod(true));
}
else
{
throw new ArgumentException();
}
}
}
}
|