From 1d1a9d7933f34bb2ed1aa8daefbbdec14b204c8c Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sat, 9 Apr 2011 21:17:05 +0900 Subject: [PATCH 01/12] import C# implementation --- .gitignore | 7 + csharp/msgpack.sln | 26 +++ csharp/msgpack.tests/AssemblyInfo.cs | 36 ++++ csharp/msgpack.tests/msgpack.tests.csproj | 62 ++++++ csharp/msgpack/AssemblyInfo.cs | 36 ++++ csharp/msgpack/BoxingPacker.cs | 148 +++++++++++++ csharp/msgpack/MsgPackReader.cs | 169 +++++++++++++++ csharp/msgpack/MsgPackWriter.cs | 246 ++++++++++++++++++++++ csharp/msgpack/TypePrefixes.cs | 32 +++ csharp/msgpack/msgpack.csproj | 53 +++++ 10 files changed, 815 insertions(+) create mode 100644 csharp/msgpack.sln create mode 100644 csharp/msgpack.tests/AssemblyInfo.cs create mode 100644 csharp/msgpack.tests/msgpack.tests.csproj create mode 100644 csharp/msgpack/AssemblyInfo.cs create mode 100644 csharp/msgpack/BoxingPacker.cs create mode 100644 csharp/msgpack/MsgPackReader.cs create mode 100644 csharp/msgpack/MsgPackWriter.cs create mode 100644 csharp/msgpack/TypePrefixes.cs create mode 100644 csharp/msgpack/msgpack.csproj diff --git a/.gitignore b/.gitignore index b39017b..45b7161 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,10 @@ ruby/Makefile *.6 _obj _test +/csharp/msgpack.suo +/csharp/msgpack/bin +/csharp/msgpack/obj +/csharp/msgpack/msgpack.csproj.user +/csharp/msgpack.tests/obj +/csharp/msgpack.tests/bin +/csharp/msgpack.tests/msgpack.tests.csproj.user diff --git a/csharp/msgpack.sln b/csharp/msgpack.sln new file mode 100644 index 0000000..351c7b8 --- /dev/null +++ b/csharp/msgpack.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "msgpack", "msgpack\msgpack.csproj", "{E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "msgpack.tests", "msgpack.tests\msgpack.tests.csproj", "{CE24167B-8F0A-4670-BD1E-3C283311E86B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}.Release|Any CPU.Build.0 = Release|Any CPU + {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/csharp/msgpack.tests/AssemblyInfo.cs b/csharp/msgpack.tests/AssemblyInfo.cs new file mode 100644 index 0000000..de7e181 --- /dev/null +++ b/csharp/msgpack.tests/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle ("msgpack.tests")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("Microsoft")] +[assembly: AssemblyProduct ("msgpack.tests")] +[assembly: AssemblyCopyright ("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible (false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid ("82a4db7c-686b-4206-9cc9-9aae082d7e73")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion ("1.0.0.0")] +[assembly: AssemblyFileVersion ("1.0.0.0")] diff --git a/csharp/msgpack.tests/msgpack.tests.csproj b/csharp/msgpack.tests/msgpack.tests.csproj new file mode 100644 index 0000000..381bf66 --- /dev/null +++ b/csharp/msgpack.tests/msgpack.tests.csproj @@ -0,0 +1,62 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {CE24167B-8F0A-4670-BD1E-3C283311E86B} + Library + Properties + msgpack.tests + msgpack.tests + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F} + msgpack + + + + + \ No newline at end of file diff --git a/csharp/msgpack/AssemblyInfo.cs b/csharp/msgpack/AssemblyInfo.cs new file mode 100644 index 0000000..0ef2ef9 --- /dev/null +++ b/csharp/msgpack/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle ("msgpack")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("Microsoft")] +[assembly: AssemblyProduct ("msgpack")] +[assembly: AssemblyCopyright ("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible (false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid ("aae99974-7a7d-4787-83ca-614779d54bd2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion ("1.0.0.0")] +[assembly: AssemblyFileVersion ("1.0.0.0")] diff --git a/csharp/msgpack/BoxingPacker.cs b/csharp/msgpack/BoxingPacker.cs new file mode 100644 index 0000000..c513a30 --- /dev/null +++ b/csharp/msgpack/BoxingPacker.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +namespace msgpack +{ + public class BoxingPacker + { + static Type KeyValuePairDefinitionType; + + static BoxingPacker () + { + KeyValuePairDefinitionType = typeof (KeyValuePair).GetGenericTypeDefinition (); + } + + public void Pack (Stream strm, object o) + { + 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 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[] (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); + } + + 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 dic = new Dictionary ((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 (); + } + } + } +} diff --git a/csharp/msgpack/MsgPackReader.cs b/csharp/msgpack/MsgPackReader.cs new file mode 100644 index 0000000..aea3825 --- /dev/null +++ b/csharp/msgpack/MsgPackReader.cs @@ -0,0 +1,169 @@ +using System; +using System.IO; + +namespace msgpack +{ + public class MsgPackReader + { + Stream _strm; + byte[] _tmp0 = new byte[8]; + byte[] _tmp1 = new byte[8]; + + 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 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; + 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); + } + } +} diff --git a/csharp/msgpack/MsgPackWriter.cs b/csharp/msgpack/MsgPackWriter.cs new file mode 100644 index 0000000..1942135 --- /dev/null +++ b/csharp/msgpack/MsgPackWriter.cs @@ -0,0 +1,246 @@ +using System; +using System.IO; +using System.Text; + +namespace msgpack +{ + public class MsgPackWriter + { + Stream _strm; + Encoding _encoding = Encoding.UTF8; + byte[] _tmp = new byte[9]; + + 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 (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, 0x96, 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 (_encoding.GetBytes (x)); + } + } +} diff --git a/csharp/msgpack/TypePrefixes.cs b/csharp/msgpack/TypePrefixes.cs new file mode 100644 index 0000000..633991b --- /dev/null +++ b/csharp/msgpack/TypePrefixes.cs @@ -0,0 +1,32 @@ +namespace msgpack +{ + 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 + } +} diff --git a/csharp/msgpack/msgpack.csproj b/csharp/msgpack/msgpack.csproj new file mode 100644 index 0000000..237becc --- /dev/null +++ b/csharp/msgpack/msgpack.csproj @@ -0,0 +1,53 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F} + Library + Properties + msgpack + msgpack + v4.0 + 512 + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + \ No newline at end of file From 0b45e9442b4ee9bb905274768e249d4269472022 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sat, 9 Apr 2011 21:22:15 +0900 Subject: [PATCH 02/12] csharp: add type check helper --- csharp/msgpack/MsgPackReader.cs | 41 +++++++++++++++++++++++++++++++++ csharp/msgpack/MsgPackWriter.cs | 8 +++---- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/csharp/msgpack/MsgPackReader.cs b/csharp/msgpack/MsgPackReader.cs index aea3825..7f28132 100644 --- a/csharp/msgpack/MsgPackReader.cs +++ b/csharp/msgpack/MsgPackReader.cs @@ -28,6 +28,47 @@ namespace msgpack 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 IsSigned64 () + { + return this.Type == TypePrefixes.Int64; + } + + public bool IsUnsigned () + { + return 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; diff --git a/csharp/msgpack/MsgPackWriter.cs b/csharp/msgpack/MsgPackWriter.cs index 1942135..518e471 100644 --- a/csharp/msgpack/MsgPackWriter.cs +++ b/csharp/msgpack/MsgPackWriter.cs @@ -15,7 +15,7 @@ namespace msgpack _strm = strm; } - public void Write (byte x) + void Write (byte x) { if (x < 128) { _strm.WriteByte (x); @@ -27,7 +27,7 @@ namespace msgpack } } - public void Write (ushort x) + void Write (ushort x) { if (x < 0x100) { Write ((byte)x); @@ -74,7 +74,7 @@ namespace msgpack } } - public void Write (sbyte x) + void Write (sbyte x) { if (x >= -32 && x <= -1) { _strm.WriteByte ((byte)(0xe0 | (byte)x)); @@ -88,7 +88,7 @@ namespace msgpack } } - public void Write (short x) + void Write (short x) { if (x >= sbyte.MinValue && x <= sbyte.MaxValue) { Write ((sbyte)x); From 8949551c2e3f90d7d682d38f48004fb65bc0c44e Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sat, 9 Apr 2011 22:12:44 +0900 Subject: [PATCH 03/12] Add MsgPackReader/MsgPackWriter unit tests --- csharp/msgpack.tests/ReaderWriterTests.cs | 330 ++++++++++++++++++++++ csharp/msgpack.tests/msgpack.tests.csproj | 13 +- 2 files changed, 336 insertions(+), 7 deletions(-) create mode 100644 csharp/msgpack.tests/ReaderWriterTests.cs diff --git a/csharp/msgpack.tests/ReaderWriterTests.cs b/csharp/msgpack.tests/ReaderWriterTests.cs new file mode 100644 index 0000000..5faeae0 --- /dev/null +++ b/csharp/msgpack.tests/ReaderWriterTests.cs @@ -0,0 +1,330 @@ +#define NUNIT + +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using System.IO; + +#if !NUNIT +#error Currently, Not Supported +using Microsoft.VisualStudio.TestTools.UnitTesting; +#else +using NUnit.Framework; +using TestClass = NUnit.Framework.TestFixtureAttribute; +using TestInitialize = NUnit.Framework.SetUpAttribute; +using TestCleanup = NUnit.Framework.TearDownAttribute; +using TestMethod = NUnit.Framework.TestAttribute; +#endif + +namespace msgpack.tests +{ + [TestClass] + public class ReaderWriterTests + { + [TestMethod] + public void SignedNumberTest () + { + long[] nums = new long[]{ + /* positive fixnum */ + 0, 1, 126, 127, + + /* negative fixnum */ + -1, -2, -31, -32, + + /* int8 */ + -128, -33, + + /* int16 */ + -32768, -129, 128, 32767, + + /* int32 */ + -2147483648, -32769, 32768, 2147483647, + + /* int64 */ + -9223372036854775808, -2147483649, 2147483648, 9223372036854775807 + }; + byte[] expectedBytes = new byte[] { + /* positive fixnum */ + 0, 1, 126, 127, + + /* negative fixnum */ + 0xff, 0xfe, 0xe1, 0xe0, + + /* int8 */ + 0xd0, 0x80, + 0xd0, 0xdf, + + /* int16 */ + 0xd1, 0x80, 0x00, + 0xd1, 0xff, 0x7f, + 0xd1, 0x00, 0x80, + 0xd1, 0x7f, 0xff, + + /* int32 */ + 0xd2, 0x80, 0x00, 0x00, 0x00, + 0xd2, 0xff, 0xff, 0x7f, 0xff, + 0xd2, 0x00, 0x00, 0x80, 0x00, + 0xd2, 0x7f, 0xff, 0xff, 0xff, + + /* int64 */ + 0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, + 0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + Test (delegate (MsgPackWriter writer) { + for (int i = 0; i < nums.Length; i ++) { + writer.Write (nums[i]); + } + }, delegate (MsgPackReader reader) { + for (int i = 0; i < nums.Length; i ++) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsSigned () || reader.IsSigned64 ()); + if (reader.IsSigned64 ()) { + Assert.AreEqual (nums[i], reader.ValueSigned64); + } else { + Assert.AreEqual (nums[i], reader.ValueSigned); + } + } + }, expectedBytes); + } + + [TestMethod] + public void UnsignedNumberTest () + { + ulong[] nums = new ulong[]{ + /* uint8 */ + 128, byte.MaxValue, + + /* uint16 */ + byte.MaxValue + 1, ushort.MaxValue, + + /* uint32 */ + ushort.MaxValue + 1U, uint.MaxValue, + + /* uint64 */ + uint.MaxValue + 1UL, ulong.MaxValue + }; + byte[] expectedBytes = new byte[] { + /* int8 */ + 0xcc, 0x80, + 0xcc, 0xff, + + /* int16 */ + 0xcd, 0x01, 0x00, + 0xcd, 0xff, 0xff, + + /* int32 */ + 0xce, 0x00, 0x01, 0x00, 0x00, + 0xce, 0xff, 0xff, 0xff, 0xff, + + /* int64 */ + 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + Test (delegate (MsgPackWriter writer) { + for (int i = 0; i < nums.Length; i ++) { + writer.Write (nums[i]); + } + }, delegate (MsgPackReader reader) { + for (int i = 0; i < nums.Length; i ++) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsUnsigned () || reader.IsUnsigned64 ()); + if (reader.IsUnsigned64 ()) { + Assert.AreEqual (nums[i], reader.ValueUnsigned64); + } else { + Assert.AreEqual (nums[i], reader.ValueUnsigned); + } + } + }, expectedBytes); + } + + [TestMethod] + public void NilTest () + { + byte[] expectedBytes = new byte[] { + 0xc0 + }; + + Test (delegate (MsgPackWriter writer) { + writer.WriteNil (); + }, delegate (MsgPackReader reader) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.Nil); + }, expectedBytes); + } + + [TestMethod] + public void BooleanTest () + { + byte[] expectedBytes = new byte[] { + 0xc3, 0xc2 + }; + + Test (delegate (MsgPackWriter writer) { + writer.Write (true); + writer.Write (false); + }, delegate (MsgPackReader reader) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.True); + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.False); + }, expectedBytes); + } + + [TestMethod] + public void FloatingPointTest () + { + byte[] expectedBytes = new byte[] { + 0xca, 0x40, 0x49, 0x0f, 0xdb, + 0xcb, 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, + }; + + Test (delegate (MsgPackWriter writer) { + writer.Write ((float)Math.PI); + writer.Write (Math.PI); + }, delegate (MsgPackReader reader) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.Float); + Assert.AreEqual ((float)Math.PI, reader.ValueFloat); + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.Type == TypePrefixes.Double); + Assert.AreEqual (Math.PI, reader.ValueDouble); + }, expectedBytes); + } + + [TestMethod] + public void RawTest () + { + Random rnd = new Random (); + + byte[][] rawList = new byte[][] { + new byte[0], + new byte[1], + new byte[31], + new byte[32], + new byte[65535], + new byte[65536] + }; + byte[][] headerSizeList = new byte[][] { + new byte[] {0xa0}, + new byte[] {0xa1}, + new byte[] {0xbf}, + new byte[] {0xda, 0x00, 0x20}, + new byte[] {0xda, 0xff, 0xff}, + new byte[] {0xdb, 0x00, 0x01, 0x00, 0x00}, + }; + byte[] expectedBytes = new byte[131135 + 1 * 3 + 3 * 2 + 5]; + for (int i = 0, offset = 0; i < rawList.Length; i ++) { + rnd.NextBytes (rawList[i]); + + Buffer.BlockCopy (headerSizeList[i], 0, expectedBytes, offset, headerSizeList[i].Length); + offset += headerSizeList[i].Length; + Buffer.BlockCopy (rawList[i], 0, expectedBytes, offset, rawList[i].Length); + offset += rawList[i].Length; + } + + Test (delegate (MsgPackWriter writer) { + for (int i = 0; i < rawList.Length; i ++) + writer.Write (rawList[i]); + }, delegate (MsgPackReader reader) { + for (int i = 0; i < rawList.Length; i ++) { + Assert.IsTrue (reader.Read ()); + Assert.AreEqual (rawList[i].Length, (int)reader.Length); + byte[] tmp = new byte[(int)reader.Length]; + reader.ReadValueRaw (tmp, 0, tmp.Length); + Assert.AreEqual (rawList[i], tmp); + } + }, expectedBytes); + } + + [TestMethod] + public void ArrayMapRawHeaderTest () + { + int[] list = new int[] { + 0, 1, 15, 16, 31, 32, 65535, 65536 + }; + byte[] expectedBytes = new byte[] { + /* size=0 */ + 0x90, /* array */ + 0x80, /* map */ + 0xa0, /* raw */ + + /* size=1 */ + 0x91, + 0x81, + 0xa1, + + /* size=15 */ + 0x9f, + 0x8f, + 0xaf, + + /* size=16 */ + 0xdc, 0x00, 0x10, /* array16 */ + 0xde, 0x00, 0x10, /* map16 */ + 0xb0, /* fix raw */ + + /* size=31 */ + 0xdc, 0x00, 0x1f, /* array16 */ + 0xde, 0x00, 0x1f, /* map16 */ + 0xbf, /* fix raw */ + + /* size=32 */ + 0xdc, 0x00, 0x20, /* array16 */ + 0xde, 0x00, 0x20, /* map16 */ + 0xda, 0x00, 0x20, /* raw16 */ + + /* size=65535 */ + 0xdc, 0xff, 0xff, /* array16 */ + 0xde, 0xff, 0xff, /* map16 */ + 0xda, 0xff, 0xff, /* raw16 */ + + /* size=65536 */ + 0xdd, 0x00, 0x01, 0x00, 0x00, /* array32 */ + 0xdf, 0x00, 0x01, 0x00, 0x00, /* map32 */ + 0xdb, 0x00, 0x01, 0x00, 0x00, /* raw32 */ + }; + + Test (delegate (MsgPackWriter writer) { + for (int i = 0; i < list.Length; i ++) { + writer.WriteArrayHeader (list[i]); + writer.WriteMapHeader (list[i]); + writer.WriteRawHeader (list[i]); + } + }, delegate (MsgPackReader reader) { + for (int i = 0; i < list.Length; i ++) { + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsArray ()); + Assert.AreEqual (list[i], (int)reader.Length); + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsMap ()); + Assert.AreEqual (list[i], (int)reader.Length); + Assert.IsTrue (reader.Read ()); + Assert.IsTrue (reader.IsRaw ()); + Assert.AreEqual (list[i], (int)reader.Length); + } + }, expectedBytes); + } + + delegate void WriteDelegate (MsgPackWriter writer); + delegate void ReadDelegate (MsgPackReader reader); + void Test (WriteDelegate writeProc, ReadDelegate readProc, byte[] expectedBytes) + { + byte[] raw; + using (MemoryStream ms = new MemoryStream ()) { + MsgPackWriter writer = new MsgPackWriter (ms); + writeProc (writer); + raw = ms.ToArray (); + } + Assert.AreEqual (expectedBytes, raw, "pack failed"); + using (MemoryStream ms = new MemoryStream (raw)) { + MsgPackReader reader = new MsgPackReader (ms); + readProc (reader); + } + } + } +} diff --git a/csharp/msgpack.tests/msgpack.tests.csproj b/csharp/msgpack.tests/msgpack.tests.csproj index 381bf66..4a9f287 100644 --- a/csharp/msgpack.tests/msgpack.tests.csproj +++ b/csharp/msgpack.tests/msgpack.tests.csproj @@ -1,4 +1,4 @@ - + Debug @@ -12,13 +12,14 @@ msgpack.tests v4.0 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} true full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG prompt 4 @@ -34,16 +35,14 @@ + + - - - - - + From 8e923777b870c9ab7f1e52b375846fd00535d8a1 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sat, 9 Apr 2011 22:16:24 +0900 Subject: [PATCH 04/12] csharp: fix fixraw prefix --- csharp/msgpack/MsgPackWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/msgpack/MsgPackWriter.cs b/csharp/msgpack/MsgPackWriter.cs index 518e471..8db861f 100644 --- a/csharp/msgpack/MsgPackWriter.cs +++ b/csharp/msgpack/MsgPackWriter.cs @@ -201,7 +201,7 @@ namespace msgpack public void WriteRawHeader (int N) { - WriteLengthHeader (N, 32, 0x96, 0xda, 0xdb); + WriteLengthHeader (N, 32, 0xa0, 0xda, 0xdb); } public void WriteArrayHeader (int N) From 05ac2603e6e8219b4cb588d2e53eaaf016f24672 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sun, 10 Apr 2011 01:06:26 +0900 Subject: [PATCH 05/12] csharp: add BoxingPacker tests --- csharp/msgpack.tests/BoxingPackerTests.cs | 85 +++++++++++++++++++++++ csharp/msgpack.tests/msgpack.tests.csproj | 5 +- csharp/msgpack/BoxingPacker.cs | 20 ++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 csharp/msgpack.tests/BoxingPackerTests.cs diff --git a/csharp/msgpack.tests/BoxingPackerTests.cs b/csharp/msgpack.tests/BoxingPackerTests.cs new file mode 100644 index 0000000..da2209d --- /dev/null +++ b/csharp/msgpack.tests/BoxingPackerTests.cs @@ -0,0 +1,85 @@ +#define NUNIT + +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +#if !NUNIT +#error Currently, Not Supported +using Microsoft.VisualStudio.TestTools.UnitTesting; +#else +using NUnit.Framework; +using TestClass = NUnit.Framework.TestFixtureAttribute; +using TestMethod = NUnit.Framework.TestAttribute; +#endif + +namespace msgpack.tests +{ + [TestClass] + public class BoxingPackerTests + { + [TestMethod] + public void NullTest () + { + BoxingPacker packer = new BoxingPacker (); + Assert.IsNull (packer.Unpack (packer.Pack (null))); + } + + [TestMethod] + public void PrimitiveTypeTest () + { + BoxingPacker packer = new BoxingPacker (); + RoundtripTest (packer, 12345); + RoundtripTest (packer, 1234567890123456789UL); + RoundtripTest (packer, Math.PI); + RoundtripTest (packer, true); + RoundtripTest (packer, false); + } + + [TestMethod] + public void ArrayTest () + { + BoxingPacker packer = new BoxingPacker (); + RoundtripTest (packer, new object[0]); + RoundtripTest (packer, new object[]{ + int.MinValue, int.MaxValue, 1234567890123456789UL, ulong.MaxValue, + float.MinValue, float.MaxValue, float.Epsilon, float.NaN, float.PositiveInfinity, float.NegativeInfinity, + double.MinValue, double.MaxValue, double.Epsilon, double.NaN, double.PositiveInfinity, double.NegativeInfinity, + null, true, false, new object[] { + new object[] {1, 2, 3}, + new object[] {Math.PI, true} + } + }); + } + + [TestMethod] + public void MapTest () + { + BoxingPacker packer = new BoxingPacker (); + Dictionary dic = new Dictionary (); + Dictionary dic2 = new Dictionary (); + RoundtripTest> (packer, dic); + + dic2.Add (123, 456); + dic2.Add (234, 567); + dic2.Add (345, 678); + + dic.Add (0, 0.123); + dic.Add (Math.PI, true); + dic.Add (false, new object[] {1, 2, 3}); + dic.Add (1, new Dictionary (dic2)); + RoundtripTest> (packer, dic); + + dic[1] = ((Dictionary)dic[1]).ToArray (); + Assert.AreEqual (dic, packer.Unpack (packer.Pack (dic.ToArray ()))); + } + + void RoundtripTest (BoxingPacker packer, T obj) + { + T obj2 = (T)packer.Unpack (packer.Pack (obj)); + Assert.AreEqual (obj, obj2); + } + } +} diff --git a/csharp/msgpack.tests/msgpack.tests.csproj b/csharp/msgpack.tests/msgpack.tests.csproj index 4a9f287..e610dd8 100644 --- a/csharp/msgpack.tests/msgpack.tests.csproj +++ b/csharp/msgpack.tests/msgpack.tests.csproj @@ -36,12 +36,15 @@ - + + False + + diff --git a/csharp/msgpack/BoxingPacker.cs b/csharp/msgpack/BoxingPacker.cs index c513a30..c460850 100644 --- a/csharp/msgpack/BoxingPacker.cs +++ b/csharp/msgpack/BoxingPacker.cs @@ -21,6 +21,14 @@ namespace msgpack 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) { @@ -86,6 +94,18 @@ namespace msgpack 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 ()) From ca9015452e3dbbe3075e4dbdb50e056f29461ca6 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sun, 10 Apr 2011 01:38:03 +0900 Subject: [PATCH 06/12] csharp: add Makefile --- csharp/Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 csharp/Makefile diff --git a/csharp/Makefile b/csharp/Makefile new file mode 100644 index 0000000..4f89338 --- /dev/null +++ b/csharp/Makefile @@ -0,0 +1,21 @@ +TARGET=msgpack.dll +TEST_TARGET=msgpack.tests.dll + +SRC=$(shell find msgpack -name "*.cs") +TEST_SRC=$(shell find msgpack.tests -name "*.cs") + +MONO_CC=mcs +NUNIT_CONSOLE=nunit-console + +all: $(TARGET) +test: $(TEST_TARGET) $(TARGET) +clean: + rm -f $(TARGET) $(TEST_TARGET) +run-test: + $(NUNIT_CONSOLE) $(TEST_TARGET) + +$(TARGET): $(SRC) + $(MONO_CC) -out:$@ -t:library -unsafe+ $^ + +$(TEST_TARGET): $(TEST_SRC) + $(MONO_CC) -out:$@ -t:library -r:$(TARGET) -r:nunit.framework.dll $^ From 68a98d3dd0fe71a0f4a99e04504b1770bc8eec00 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sun, 10 Apr 2011 02:03:40 +0900 Subject: [PATCH 07/12] csharp: remove reference Microsoft.VisualStudio.QualityTools.UnitTestFramework --- csharp/msgpack.tests/BoxingPackerTests.cs | 24 +++++------------ csharp/msgpack.tests/ReaderWriterTests.cs | 33 +++++++---------------- csharp/msgpack.tests/msgpack.tests.csproj | 1 - 3 files changed, 15 insertions(+), 43 deletions(-) diff --git a/csharp/msgpack.tests/BoxingPackerTests.cs b/csharp/msgpack.tests/BoxingPackerTests.cs index da2209d..cd63129 100644 --- a/csharp/msgpack.tests/BoxingPackerTests.cs +++ b/csharp/msgpack.tests/BoxingPackerTests.cs @@ -1,33 +1,21 @@ -#define NUNIT - -using System; -using System.Text; -using System.Collections; +using System; using System.Collections.Generic; using System.Linq; - -#if !NUNIT -#error Currently, Not Supported -using Microsoft.VisualStudio.TestTools.UnitTesting; -#else using NUnit.Framework; -using TestClass = NUnit.Framework.TestFixtureAttribute; -using TestMethod = NUnit.Framework.TestAttribute; -#endif namespace msgpack.tests { - [TestClass] + [TestFixture] public class BoxingPackerTests { - [TestMethod] + [Test] public void NullTest () { BoxingPacker packer = new BoxingPacker (); Assert.IsNull (packer.Unpack (packer.Pack (null))); } - [TestMethod] + [Test] public void PrimitiveTypeTest () { BoxingPacker packer = new BoxingPacker (); @@ -38,7 +26,7 @@ namespace msgpack.tests RoundtripTest (packer, false); } - [TestMethod] + [Test] public void ArrayTest () { BoxingPacker packer = new BoxingPacker (); @@ -54,7 +42,7 @@ namespace msgpack.tests }); } - [TestMethod] + [Test] public void MapTest () { BoxingPacker packer = new BoxingPacker (); diff --git a/csharp/msgpack.tests/ReaderWriterTests.cs b/csharp/msgpack.tests/ReaderWriterTests.cs index 5faeae0..10c6f70 100644 --- a/csharp/msgpack.tests/ReaderWriterTests.cs +++ b/csharp/msgpack.tests/ReaderWriterTests.cs @@ -1,28 +1,13 @@ -#define NUNIT - -using System; -using System.Text; -using System.Collections.Generic; -using System.Linq; +using System; using System.IO; - -#if !NUNIT -#error Currently, Not Supported -using Microsoft.VisualStudio.TestTools.UnitTesting; -#else using NUnit.Framework; -using TestClass = NUnit.Framework.TestFixtureAttribute; -using TestInitialize = NUnit.Framework.SetUpAttribute; -using TestCleanup = NUnit.Framework.TearDownAttribute; -using TestMethod = NUnit.Framework.TestAttribute; -#endif namespace msgpack.tests { - [TestClass] + [TestFixture] public class ReaderWriterTests { - [TestMethod] + [Test] public void SignedNumberTest () { long[] nums = new long[]{ @@ -91,7 +76,7 @@ namespace msgpack.tests }, expectedBytes); } - [TestMethod] + [Test] public void UnsignedNumberTest () { ulong[] nums = new ulong[]{ @@ -142,7 +127,7 @@ namespace msgpack.tests }, expectedBytes); } - [TestMethod] + [Test] public void NilTest () { byte[] expectedBytes = new byte[] { @@ -157,7 +142,7 @@ namespace msgpack.tests }, expectedBytes); } - [TestMethod] + [Test] public void BooleanTest () { byte[] expectedBytes = new byte[] { @@ -175,7 +160,7 @@ namespace msgpack.tests }, expectedBytes); } - [TestMethod] + [Test] public void FloatingPointTest () { byte[] expectedBytes = new byte[] { @@ -196,7 +181,7 @@ namespace msgpack.tests }, expectedBytes); } - [TestMethod] + [Test] public void RawTest () { Random rnd = new Random (); @@ -241,7 +226,7 @@ namespace msgpack.tests }, expectedBytes); } - [TestMethod] + [Test] public void ArrayMapRawHeaderTest () { int[] list = new int[] { diff --git a/csharp/msgpack.tests/msgpack.tests.csproj b/csharp/msgpack.tests/msgpack.tests.csproj index e610dd8..5d27a80 100644 --- a/csharp/msgpack.tests/msgpack.tests.csproj +++ b/csharp/msgpack.tests/msgpack.tests.csproj @@ -35,7 +35,6 @@ - False From 60643f023ffbb7a62740b18369b1e7200318ec21 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sun, 10 Apr 2011 12:52:14 +0900 Subject: [PATCH 08/12] csharp: add ObjectPacker --- csharp/msgpack.tests/ObjectPackerTests.cs | 95 ++++++++++ csharp/msgpack.tests/msgpack.tests.csproj | 1 + csharp/msgpack/MsgPackReader.cs | 9 +- csharp/msgpack/MsgPackWriter.cs | 8 +- csharp/msgpack/ObjectPacker.cs | 220 ++++++++++++++++++++++ csharp/msgpack/ReflectionCache.cs | 44 +++++ csharp/msgpack/ReflectionCacheEntry.cs | 28 +++ csharp/msgpack/msgpack.csproj | 5 +- 8 files changed, 404 insertions(+), 6 deletions(-) create mode 100644 csharp/msgpack.tests/ObjectPackerTests.cs create mode 100644 csharp/msgpack/ObjectPacker.cs create mode 100644 csharp/msgpack/ReflectionCache.cs create mode 100644 csharp/msgpack/ReflectionCacheEntry.cs diff --git a/csharp/msgpack.tests/ObjectPackerTests.cs b/csharp/msgpack.tests/ObjectPackerTests.cs new file mode 100644 index 0000000..b52e87c --- /dev/null +++ b/csharp/msgpack.tests/ObjectPackerTests.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace msgpack.tests +{ + [TestFixture] + public class ObjectPackerTests + { + public static void Main () + { + ObjectPackerTests tests = new ObjectPackerTests (); + tests.TestA (); + } + + [Test] + public void TestA () + { + ObjectPacker packer = new ObjectPacker (); + TestA_Class obj0 = new TestA_Class (); + TestA_Class obj1 = packer.Unpack (packer.Pack (obj0)); + obj0.Check (obj1); + } + + [Test] + public void TestB () + { + ObjectPacker packer = new ObjectPacker (); + Dictionary dic = new Dictionary (); + Random rnd = new Random (); + int size = rnd.Next () & 0xff; + for (int i = 0; i < size; i ++) + dic[rnd.Next()] = rnd.Next (); + Dictionary dic_ = packer.Unpack> (packer.Pack (dic)); + Assert.AreEqual (dic, dic_); + } + + class TestA_Class + { + public bool a; + public byte b; + public sbyte c; + public short d; + public ushort e; + public int f; + public uint g; + public long h; + public ulong i; + public float j; + public double k; + public int[] l; + public string m; + + public TestA_Class () + { + Random rnd = new Random (); + a = rnd.NextDouble () < 0.5; + b = (byte)rnd.Next (); + c = (sbyte)rnd.Next (); + d = (short)rnd.Next (); + e = (ushort)rnd.Next (); + f = (int)rnd.Next (); + g = (uint)rnd.Next (); + h = (long)rnd.Next (); + i = (ulong)rnd.Next (); + j = (float)rnd.NextDouble (); + k = (double)rnd.NextDouble (); + l = new int[rnd.Next () & 0xff]; + for (int z = 0; z < l.Length; z ++) + l[z] = rnd.Next (); + + byte[] buf = new byte[rnd.Next() & 0xff]; + rnd.NextBytes (buf); + m = Convert.ToBase64String (buf); + } + + public void Check (TestA_Class other) + { + Assert.AreEqual (this.a, other.a); + Assert.AreEqual (this.b, other.b); + Assert.AreEqual (this.c, other.c); + Assert.AreEqual (this.d, other.d); + Assert.AreEqual (this.e, other.e); + Assert.AreEqual (this.f, other.f); + Assert.AreEqual (this.g, other.g); + Assert.AreEqual (this.h, other.h); + Assert.AreEqual (this.i, other.i); + Assert.AreEqual (this.j, other.j); + Assert.AreEqual (this.k, other.k); + Assert.AreEqual (this.l, other.l); + Assert.AreEqual (this.m, other.m); + } + } + } +} diff --git a/csharp/msgpack.tests/msgpack.tests.csproj b/csharp/msgpack.tests/msgpack.tests.csproj index 5d27a80..15ceda9 100644 --- a/csharp/msgpack.tests/msgpack.tests.csproj +++ b/csharp/msgpack.tests/msgpack.tests.csproj @@ -44,6 +44,7 @@ + diff --git a/csharp/msgpack/MsgPackReader.cs b/csharp/msgpack/MsgPackReader.cs index 7f28132..1a338e7 100644 --- a/csharp/msgpack/MsgPackReader.cs +++ b/csharp/msgpack/MsgPackReader.cs @@ -37,6 +37,11 @@ namespace msgpack this.Type == TypePrefixes.Int32; } + public bool IsBoolean () + { + return this.Type == TypePrefixes.True || this.Type == TypePrefixes.False; + } + public bool IsSigned64 () { return this.Type == TypePrefixes.Int64; @@ -44,7 +49,8 @@ namespace msgpack public bool IsUnsigned () { - return this.Type == TypePrefixes.UInt8 || + return this.Type == TypePrefixes.PositiveFixNum || + this.Type == TypePrefixes.UInt8 || this.Type == TypePrefixes.UInt16 || this.Type == TypePrefixes.UInt32; } @@ -132,6 +138,7 @@ namespace msgpack break; case TypePrefixes.PositiveFixNum: ValueSigned = x & 0x7f; + ValueUnsigned = (uint)ValueSigned; break; case TypePrefixes.UInt8: x = _strm.ReadByte (); diff --git a/csharp/msgpack/MsgPackWriter.cs b/csharp/msgpack/MsgPackWriter.cs index 8db861f..abda9c0 100644 --- a/csharp/msgpack/MsgPackWriter.cs +++ b/csharp/msgpack/MsgPackWriter.cs @@ -15,7 +15,7 @@ namespace msgpack _strm = strm; } - void Write (byte x) + public void Write (byte x) { if (x < 128) { _strm.WriteByte (x); @@ -27,7 +27,7 @@ namespace msgpack } } - void Write (ushort x) + public void Write (ushort x) { if (x < 0x100) { Write ((byte)x); @@ -74,7 +74,7 @@ namespace msgpack } } - void Write (sbyte x) + public void Write (sbyte x) { if (x >= -32 && x <= -1) { _strm.WriteByte ((byte)(0xe0 | (byte)x)); @@ -88,7 +88,7 @@ namespace msgpack } } - void Write (short x) + public void Write (short x) { if (x >= sbyte.MinValue && x <= sbyte.MaxValue) { Write ((sbyte)x); diff --git a/csharp/msgpack/ObjectPacker.cs b/csharp/msgpack/ObjectPacker.cs new file mode 100644 index 0000000..c352995 --- /dev/null +++ b/csharp/msgpack/ObjectPacker.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; + +namespace msgpack +{ + public class ObjectPacker + { + byte[] _buf = new byte[64]; + Encoding _encoding = Encoding.UTF8; + static Dictionary PackerMapping; + static Dictionary UnpackerMapping; + + delegate void PackDelegate (ObjectPacker packer, MsgPackWriter writer, object o); + delegate object UnpackDelegate (ObjectPacker packer, MsgPackReader reader); + + static ObjectPacker () + { + PackerMapping = new Dictionary (); + UnpackerMapping = new Dictionary (); + + 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)) || t.Equals (typeof (char))) writer.Write ((ushort)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 pair in entry.FieldMap) { + writer.Write (pair.Key); + 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 (byte[] buf) + { + return Unpack (buf, 0, buf.Length); + } + + public T Unpack (byte[] buf, int offset, int size) + { + using (MemoryStream ms = new MemoryStream (buf, offset, size)) { + return Unpack (ms); + } + } + + public T Unpack (Stream strm) + { + if (typeof (T).IsPrimitive) + throw new NotSupportedException (); + MsgPackReader reader = new MsgPackReader (strm); + return (T)Unpack (reader, typeof (T)); + } + + 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 ()) + throw new FormatException (); + 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 (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); + } + } +} diff --git a/csharp/msgpack/ReflectionCache.cs b/csharp/msgpack/ReflectionCache.cs new file mode 100644 index 0000000..d7f9726 --- /dev/null +++ b/csharp/msgpack/ReflectionCache.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; + +namespace msgpack +{ + public static class ReflectionCache + { + static Dictionary _cache; + + static ReflectionCache () + { + _cache = new Dictionary (); + } + + 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 (); + } + } + } +} diff --git a/csharp/msgpack/ReflectionCacheEntry.cs b/csharp/msgpack/ReflectionCacheEntry.cs new file mode 100644 index 0000000..9a27f70 --- /dev/null +++ b/csharp/msgpack/ReflectionCacheEntry.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace msgpack +{ + 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 map = new Dictionary (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 (\<.+\>) + map[name] = f; + } + FieldMap = map; + } + + public IDictionary FieldMap { get; private set; } + } +} diff --git a/csharp/msgpack/msgpack.csproj b/csharp/msgpack/msgpack.csproj index 237becc..1a778ae 100644 --- a/csharp/msgpack/msgpack.csproj +++ b/csharp/msgpack/msgpack.csproj @@ -1,4 +1,4 @@ - + Debug @@ -40,6 +40,9 @@ + + + From 0812eb1c0432f34aafaf3d5c6f9721db8861039d Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sat, 16 Apr 2011 21:12:04 +0900 Subject: [PATCH 09/12] add System.Reflection.Emit based CompiledPacker implementation --- csharp/msgpack.tests/CompiledPackerTests.cs | 28 + csharp/msgpack.tests/ObjectPackerTests.cs | 49 +- csharp/msgpack.tests/msgpack.tests.csproj | 1 + csharp/msgpack/CompiledPacker.cs | 72 +++ csharp/msgpack/Compiler/EmitExtensions.cs | 178 ++++++ csharp/msgpack/Compiler/PackerCompiler.cs | 643 ++++++++++++++++++++ csharp/msgpack/Compiler/Variable.cs | 30 + csharp/msgpack/Compiler/VariableType.cs | 13 + csharp/msgpack/MsgPackReader.cs | 25 + csharp/msgpack/MsgPackWriter.cs | 52 +- csharp/msgpack/ObjectPacker.cs | 6 +- csharp/msgpack/msgpack.csproj | 9 +- 12 files changed, 1087 insertions(+), 19 deletions(-) create mode 100644 csharp/msgpack.tests/CompiledPackerTests.cs create mode 100644 csharp/msgpack/CompiledPacker.cs create mode 100644 csharp/msgpack/Compiler/EmitExtensions.cs create mode 100644 csharp/msgpack/Compiler/PackerCompiler.cs create mode 100644 csharp/msgpack/Compiler/Variable.cs create mode 100644 csharp/msgpack/Compiler/VariableType.cs diff --git a/csharp/msgpack.tests/CompiledPackerTests.cs b/csharp/msgpack.tests/CompiledPackerTests.cs new file mode 100644 index 0000000..8e5a516 --- /dev/null +++ b/csharp/msgpack.tests/CompiledPackerTests.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using TestA_Class = msgpack.tests.ObjectPackerTests.TestA_Class; +using TestB_Class = msgpack.tests.ObjectPackerTests.TestB_Class; + +namespace msgpack.tests +{ + [TestFixture] + public class CompiledPackerTests + { + [Test] + public void TestA () + { + TestA_Class obj0 = new TestA_Class (); + TestA_Class obj1 = CompiledPacker.Unpack (CompiledPacker.Pack (obj0)); + obj0.Check (obj1); + } + + [Test] + public void TestB () + { + TestB_Class obj0 = TestB_Class.Create (); + TestB_Class obj1 = CompiledPacker.Unpack (CompiledPacker.Pack (obj0)); + obj0.Check (obj1); + } + } +} diff --git a/csharp/msgpack.tests/ObjectPackerTests.cs b/csharp/msgpack.tests/ObjectPackerTests.cs index b52e87c..70ec9e0 100644 --- a/csharp/msgpack.tests/ObjectPackerTests.cs +++ b/csharp/msgpack.tests/ObjectPackerTests.cs @@ -7,12 +7,6 @@ namespace msgpack.tests [TestFixture] public class ObjectPackerTests { - public static void Main () - { - ObjectPackerTests tests = new ObjectPackerTests (); - tests.TestA (); - } - [Test] public void TestA () { @@ -26,16 +20,12 @@ namespace msgpack.tests public void TestB () { ObjectPacker packer = new ObjectPacker (); - Dictionary dic = new Dictionary (); - Random rnd = new Random (); - int size = rnd.Next () & 0xff; - for (int i = 0; i < size; i ++) - dic[rnd.Next()] = rnd.Next (); - Dictionary dic_ = packer.Unpack> (packer.Pack (dic)); - Assert.AreEqual (dic, dic_); + TestB_Class obj0 = TestB_Class.Create (); + TestB_Class obj1 = packer.Unpack (packer.Pack (obj0)); + obj0.Check (obj1); } - class TestA_Class + public class TestA_Class { public bool a; public byte b; @@ -91,5 +81,36 @@ namespace msgpack.tests Assert.AreEqual (this.m, other.m); } } + + public class TestB_Class + { + public TestA_Class x; + public TestB_Class nested; + public int[] list; + + public static TestB_Class Create () + { + return Create (0); + } + + static TestB_Class Create (int level) + { + TestB_Class obj = new TestB_Class (); + obj.x = new TestA_Class (); + if (level < 10) + obj.nested = Create (level + 1); + if ((level % 2) == 0) + obj.list = new int[] {level, 0, level, int.MaxValue, level}; + return obj; + } + + public void Check (TestB_Class other) + { + x.Check (other.x); + if (nested != null) + nested.Check (other.nested); + Assert.AreEqual (list, other.list); + } + } } } diff --git a/csharp/msgpack.tests/msgpack.tests.csproj b/csharp/msgpack.tests/msgpack.tests.csproj index 15ceda9..1991021 100644 --- a/csharp/msgpack.tests/msgpack.tests.csproj +++ b/csharp/msgpack.tests/msgpack.tests.csproj @@ -44,6 +44,7 @@ + diff --git a/csharp/msgpack/CompiledPacker.cs b/csharp/msgpack/CompiledPacker.cs new file mode 100644 index 0000000..7bb6b62 --- /dev/null +++ b/csharp/msgpack/CompiledPacker.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using msgpack.Compiler; + +namespace msgpack +{ + public class CompiledPacker + { + public static byte[] Pack (object o) + { + using (MemoryStream ms = new MemoryStream ()) { + Pack (ms, o); + return ms.ToArray (); + } + } + + public static void Pack (Stream strm, object o) + { + PackerCompiler.GetPackMethod (o.GetType ()) (new MsgPackWriter (strm), o); + } + + public static byte[] Pack (T o) + { + using (MemoryStream ms = new MemoryStream ()) { + Pack (ms, o); + return ms.ToArray (); + } + } + + public static void Pack (Stream strm, T o) + { + PackerCompiler.GetPackMethod () (new MsgPackWriter (strm), o); + } + + public static T Unpack (byte[] buf) + { + return Unpack (buf, 0, buf.Length); + } + + public static T Unpack (byte[] buf, int offset, int size) + { + using (MemoryStream ms = new MemoryStream (buf, offset, size)) { + return Unpack (ms); + } + } + + public static T Unpack (Stream strm) + { + return PackerCompiler.GetUnpackMethod () (new MsgPackReader (strm)); + } + + public static object Unpack (Type t, byte[] buf) + { + return Unpack (t, buf, 0, buf.Length); + } + + public static object Unpack (Type t, byte[] buf, int offset, int size) + { + using (MemoryStream ms = new MemoryStream (buf, offset, size)) { + return Unpack (t, ms); + } + } + + public static object Unpack (Type t, Stream strm) + { + throw new NotImplementedException (); + } + } +} diff --git a/csharp/msgpack/Compiler/EmitExtensions.cs b/csharp/msgpack/Compiler/EmitExtensions.cs new file mode 100644 index 0000000..ae51e9a --- /dev/null +++ b/csharp/msgpack/Compiler/EmitExtensions.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using System.Reflection.Emit; + +namespace msgpack.Compiler +{ + 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 (); + } + } + } +} diff --git a/csharp/msgpack/Compiler/PackerCompiler.cs b/csharp/msgpack/Compiler/PackerCompiler.cs new file mode 100644 index 0000000..0776717 --- /dev/null +++ b/csharp/msgpack/Compiler/PackerCompiler.cs @@ -0,0 +1,643 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using System.Reflection.Emit; +using System.Threading; +using System.Runtime.Serialization; + +namespace msgpack.Compiler +{ + public static class PackerCompiler + { + static Dictionary CompiledPackMethods; + static Dictionary PackDelegates; + static Dictionary> PackWrapperDelegates; + + static Dictionary CompiledUnpackMethods; + static Dictionary UnpackDelegates; + static Dictionary> UnpackFieldMapping; + + static Dictionary UserDefinedPackMethods; + + static PackerCompiler () + { + CompiledPackMethods = new Dictionary (); + PackDelegates = new Dictionary (); + PackWrapperDelegates = new Dictionary> (); + UserDefinedPackMethods = new Dictionary (); + + CompiledUnpackMethods = new Dictionary (); + UnpackDelegates = new Dictionary (); + UnpackFieldMapping = new Dictionary> (); + + RegisterDefaultUnpackMethods (); + RegisterUserDefinedMethods (); + } + + #region Pack Frontend / Compiler + public static Action GetPackMethod () + { + Delegate d; + lock (CompiledPackMethods) { + PackDelegates.TryGetValue (typeof (T), out d); + } + if (d == null) + CreatePackMethod (typeof (T)); + lock (CompiledPackMethods) { + d = PackDelegates[typeof (T)]; + } + return (Action)d; + } + + public static Action GetPackMethod (Type t) + { + Action d; + lock (CompiledPackMethods) { + PackWrapperDelegates.TryGetValue (t, out d); + } + if (d == null) + CreatePackMethod (t); + lock (CompiledPackMethods) { + d = PackWrapperDelegates[t]; + } + return d; + } + + static DynamicMethod CreatePackMethod (Type t) + { + DynamicMethod methodBuilder; + lock (CompiledPackMethods) { + if (CompiledPackMethods.TryGetValue (t, out methodBuilder)) { + return CompiledPackMethods[t]; + } else { + methodBuilder = CreateDynamicMethod (typeof (void), new Type[]{typeof (MsgPackWriter), t}); + CompiledPackMethods.Add (t, methodBuilder); + CreatePackMethod (t, methodBuilder); + PackDelegates.Add (t, methodBuilder.CreateDelegate (typeof (Action<,>).MakeGenericType (typeof (MsgPackWriter), t))); + Action wrapper = CreatePackWrapper (t, methodBuilder); + PackWrapperDelegates.Add (t, wrapper); + } + } + return methodBuilder; + } + + static void CreatePackMethod (Type t, DynamicMethod methodBuilder) + { + if (t == null || methodBuilder == null) + throw new ArgumentNullException (); + if (t.IsPrimitive || t.IsInterface) + throw new NotSupportedException (); + + ILGenerator il = methodBuilder.GetILGenerator(); + + Variable arg_writer = Variable.CreateArg (0); + Variable arg_obj = Variable.CreateArg (1); + Variable local_i = Variable.CreateLocal (il.DeclareLocal (typeof (int))); + + if (!t.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); + } + + MethodInfo udm; + lock (UserDefinedPackMethods) { + UserDefinedPackMethods.TryGetValue (t, out udm); + } + if (udm != null) { + il.EmitLd (arg_writer, arg_obj); + il.Emit (OpCodes.Call, udm); + goto FinallyProcess; + } + + if (t.IsArray) { + EmitArrayWriteProcess (il, t, arg_writer, arg_obj, local_i); + goto FinallyProcess; + } + + // MsgPackWriter.WriteMapHeader + MemberInfo[] members = LookupMembers (t); + 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 (FormatMemberName (m)); + il.EmitLd_True (); + il.Emit (OpCodes.Call, typeof (MsgPackWriter).GetMethod("Write", new Type[]{typeof (string), typeof (bool)})); + + // write value + CreatePackMethod_EmitMemberValue (il, arg_writer, arg_obj, m, null, mt, t, methodBuilder); + } + +FinallyProcess: + il.Emit (OpCodes.Ret); + } + + static void EmitArrayWriteProcess (ILGenerator il, Type t, Variable var_writer, Variable var_obj, Variable var_loop) + { + 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 + CreatePackMethod_EmitMemberValue (il, var_writer, var_obj, null, var_loop, et, null, null); + + // 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); + } + + /// (optional) + /// (optional) + static void CreatePackMethod_EmitMemberValue (ILGenerator il, Variable var_writer, Variable var_obj, MemberInfo m, Variable elementIdx, Type type, Type currentType, DynamicMethod currentMethod) + { + 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 { + lock (UserDefinedPackMethods) { + UserDefinedPackMethods.TryGetValue (type, out mi); + } + if (mi == null) + mi = CreatePackMethod (type); + } + } + il.Emit (OpCodes.Call, mi); + } + + static Action CreatePackWrapper (Type t, DynamicMethod packMethod) + { + DynamicMethod dm = CreateDynamicMethod (typeof (void), new Type[] {typeof (MsgPackWriter), typeof (object)}); + ILGenerator il = dm.GetILGenerator(); + il.EmitLd (Variable.CreateArg (0), Variable.CreateArg (1)); + il.Emit (OpCodes.Castclass, t); + il.Emit (OpCodes.Call, packMethod); + il.Emit (OpCodes.Ret); + return (Action)dm.CreateDelegate (typeof (Action)); + } + #endregion + + #region Unpack Frontend / Compiler + public static Func GetUnpackMethod () + { + Delegate d; + lock (CompiledUnpackMethods) { + UnpackDelegates.TryGetValue (typeof (T), out d); + } + if (d == null) + CreateUnpackMethod (typeof (T)); + lock (CompiledUnpackMethods) { + d = UnpackDelegates[typeof (T)]; + } + return (Func)d; + } + + static MethodInfo CreateUnpackMethod (Type t) + { + MethodInfo methodBuilder; + lock (CompiledUnpackMethods) { + if (CompiledUnpackMethods.TryGetValue (t, out methodBuilder)) { + return methodBuilder; + } else { + methodBuilder = CreateDynamicMethod (t, new Type[]{typeof (MsgPackReader)}); + CompiledUnpackMethods.Add (t, methodBuilder); + UnpackFieldMapping.Add (t, new Dictionary ()); + if (t.IsArray) { + CreateUnpackArrayMethod (t, t.GetElementType (), (DynamicMethod)methodBuilder); + } else { + CreateUnpackMethod (t, (DynamicMethod)methodBuilder); + } + UnpackDelegates.Add (t, ((DynamicMethod)methodBuilder).CreateDelegate (typeof (Func<,>).MakeGenericType (typeof (MsgPackReader), t))); + } + } + return methodBuilder; + } + + static void CreateUnpackMethod (Type t, DynamicMethod methodBuilder) + { + ILGenerator il = methodBuilder.GetILGenerator (); + MethodInfo failedMethod = typeof (PackerCompiler).GetMethod ("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic); + MemberInfo[] members = LookupMembers (t); + Dictionary member_mapping = UnpackFieldMapping[t]; + for (int i = 0; i < members.Length; i ++) + member_mapping.Add (FormatMemberName (members[i]), i); + + Variable msgpackReader = Variable.CreateArg (0); + Variable obj = Variable.CreateLocal (il.DeclareLocal (t)); + 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 (Dictionary))); + Variable switch_idx = Variable.CreateLocal (il.DeclareLocal (typeof (int))); + Variable type = Variable.CreateLocal (il.DeclareLocal (typeof (Type))); + + // if (!MsgPackReader.Read()) UnpackFailed (); + // if (MsgPackReader.Type == TypePrefixes.Nil) return null; + // if (!MsgPackReader.IsMap ()) UnpackFailed (); + EmitReadAndTypeCheck (il, msgpackReader, typeof (MsgPackReader).GetMethod ("IsMap"), failedMethod, true); + + // type = typeof (T) + il.Emit (OpCodes.Ldtoken, t); + il.Emit (OpCodes.Call, typeof(Type).GetMethod ("GetTypeFromHandle")); + il.EmitSt (type); + + // mapping = LookupMemberMapping (typeof (T)) + il.EmitLd (type); + il.Emit (OpCodes.Call, typeof (PackerCompiler).GetMethod ("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic)); + il.EmitSt (mapping); + + // object o = FormatterServices.GetUninitializedObject (Type); + il.EmitLd (type); + il.Emit (OpCodes.Call, typeof (FormatterServices).GetMethod ("GetUninitializedObject")); + il.Emit (OpCodes.Castclass, t); + 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(); + EmitReadAndTypeCheck (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, (short)switch_idx.Index); + il.Emit (OpCodes.Call, typeof (Dictionary).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 mi = members[i]; + Type mt = mi.GetMemberType (); + MethodInfo unpack_method; + + il.EmitLd (obj); + if (!CompiledUnpackMethods.TryGetValue (mt, out unpack_method)) { + unpack_method = CreateUnpackMethod (mt); + } + il.EmitLd (msgpackReader); + il.Emit (OpCodes.Call, unpack_method); + il.EmitStMember (mi); + 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 CreateUnpackArrayMethod (Type arrayType, Type elementType, DynamicMethod methodBuilder) + { + ILGenerator il = methodBuilder.GetILGenerator (); + MethodInfo failedMethod = typeof (PackerCompiler).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 (); + EmitReadAndTypeCheck (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; + lock (CompiledUnpackMethods) { + if (!CompiledUnpackMethods.TryGetValue (elementType, out unpack_method)) { + unpack_method = CreateUnpackMethod (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 EmitReadAndTypeCheck (ILGenerator il, Variable msgpackReader, MethodInfo typeCheckMethod, MethodInfo failedMethod, bool nullCheckAndReturn) + { + Label lblFailed = il.DefineLabel (); + Label lblNullReturn = il.DefineLabel (); + 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); + if (nullCheckAndReturn) { + il.MarkLabel (lblNullReturn); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Ret); + } + il.MarkLabel (lblFailed); + il.Emit (OpCodes.Call, failedMethod); + il.MarkLabel (lblPassed); + } + + /// Exception Helper + static void UnpackFailed () + { + throw new FormatException (); + } + + static Dictionary LookupMemberMapping (Type t) + { + lock (CompiledUnpackMethods) { + return UnpackFieldMapping[t]; + } + } + + static void RegisterDefaultUnpackMethods () + { + BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; + MethodInfo mi = typeof (PackerCompiler).GetMethod ("Unpack_Signed", flags); + CompiledUnpackMethods.Add (typeof (sbyte), mi); + CompiledUnpackMethods.Add (typeof (short), mi); + CompiledUnpackMethods.Add (typeof (int), mi); + + mi = typeof (PackerCompiler).GetMethod ("Unpack_Signed64", flags); + CompiledUnpackMethods.Add (typeof (long), mi); + + mi = typeof (PackerCompiler).GetMethod ("Unpack_Unsigned", flags); + CompiledUnpackMethods.Add (typeof (byte), mi); + CompiledUnpackMethods.Add (typeof (ushort), mi); + CompiledUnpackMethods.Add (typeof (char), mi); + CompiledUnpackMethods.Add (typeof (uint), mi); + + mi = typeof (PackerCompiler).GetMethod ("Unpack_Unsigned64", flags); + CompiledUnpackMethods.Add (typeof (ulong), mi); + + mi = typeof (PackerCompiler).GetMethod ("Unpack_Boolean", flags); + CompiledUnpackMethods.Add (typeof (bool), mi); + + mi = typeof (PackerCompiler).GetMethod ("Unpack_Float", flags); + CompiledUnpackMethods.Add (typeof (float), mi); + + mi = typeof (PackerCompiler).GetMethod ("Unpack_Double", flags); + CompiledUnpackMethods.Add (typeof (double), mi); + + mi = typeof (PackerCompiler).GetMethod ("Unpack_String", flags); + CompiledUnpackMethods.Add (typeof (string), mi); + } + + static int Unpack_Signed (MsgPackReader reader) + { + if (!reader.Read () || !reader.IsSigned ()) + UnpackFailed (); + return reader.ValueSigned; + } + + 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 + } + + static uint Unpack_Unsigned (MsgPackReader reader) + { + if (!reader.Read () || !reader.IsUnsigned ()) + UnpackFailed (); + return reader.ValueUnsigned; + } + + 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 + } + + static bool Unpack_Boolean (MsgPackReader reader) + { + if (!reader.Read () || !reader.IsBoolean ()) + UnpackFailed (); + return reader.ValueBoolean; + } + + static float Unpack_Float (MsgPackReader reader) + { + if (!reader.Read () || reader.Type != TypePrefixes.Float) + UnpackFailed (); + return reader.ValueFloat; + } + + static double Unpack_Double (MsgPackReader reader) + { + if (!reader.Read () || reader.Type != TypePrefixes.Double) + UnpackFailed (); + return reader.ValueDouble; + } + + static string Unpack_String (MsgPackReader reader) + { + if (!reader.Read () || !reader.IsRaw ()) + UnpackFailed (); + return reader.ReadRawString (); + } + #endregion + + #region User Defined Packer/Unpackers + static void RegisterUserDefinedMethods () + { + BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; + Type type = typeof (PackerCompiler); + object[][] list = new object[][] { + new object[] {typeof (string), "PackString"} + }; + for (int i = 0; i < list.Length; i ++) + UserDefinedPackMethods.Add ((Type)list[i][0], type.GetMethod ((string)list[i][1], flags)); + } + + static void PackString (MsgPackWriter writer, string x) + { + writer.Write (x); + } + #endregion + + #region Misc + 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); + } + + static MemberInfo[] LookupMembers (Type t) + { + BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + List list = new List (); + list.AddRange (t.GetFields (baseFlags)); + //list.AddRange (t.GetProperties (baseFlags)); // TODO: + return list.ToArray (); + } + + 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 (\<.+\>) + return name; + } + + 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 + } +} diff --git a/csharp/msgpack/Compiler/Variable.cs b/csharp/msgpack/Compiler/Variable.cs new file mode 100644 index 0000000..bac3434 --- /dev/null +++ b/csharp/msgpack/Compiler/Variable.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection.Emit; + +namespace msgpack.Compiler +{ + 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; } + } +} diff --git a/csharp/msgpack/Compiler/VariableType.cs b/csharp/msgpack/Compiler/VariableType.cs new file mode 100644 index 0000000..9a0dbce --- /dev/null +++ b/csharp/msgpack/Compiler/VariableType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace msgpack.Compiler +{ + public enum VariableType + { + Local, + Arg + } +} diff --git a/csharp/msgpack/MsgPackReader.cs b/csharp/msgpack/MsgPackReader.cs index 1a338e7..06a37e0 100644 --- a/csharp/msgpack/MsgPackReader.cs +++ b/csharp/msgpack/MsgPackReader.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Text; namespace msgpack { @@ -9,6 +10,10 @@ namespace msgpack 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; @@ -213,5 +218,25 @@ namespace msgpack { 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); + } } } diff --git a/csharp/msgpack/MsgPackWriter.cs b/csharp/msgpack/MsgPackWriter.cs index abda9c0..78e347b 100644 --- a/csharp/msgpack/MsgPackWriter.cs +++ b/csharp/msgpack/MsgPackWriter.cs @@ -8,7 +8,9 @@ namespace msgpack { 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) { @@ -238,9 +240,55 @@ namespace msgpack } } - public void Write (String x) + public void Write (string x) { - Write (_encoding.GetBytes (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; + } + } } } } diff --git a/csharp/msgpack/ObjectPacker.cs b/csharp/msgpack/ObjectPacker.cs index c352995..0dabd21 100644 --- a/csharp/msgpack/ObjectPacker.cs +++ b/csharp/msgpack/ObjectPacker.cs @@ -83,7 +83,7 @@ namespace msgpack ReflectionCacheEntry entry = ReflectionCache.Lookup (t); writer.WriteMapHeader (entry.FieldMap.Count); foreach (KeyValuePair pair in entry.FieldMap) { - writer.Write (pair.Key); + writer.Write (pair.Key, _buf); object v = pair.Value.GetValue (o); if (pair.Value.FieldType.IsInterface && v != null) { writer.WriteArrayHeader (2); @@ -145,8 +145,10 @@ namespace msgpack return unpacker (this, reader); if (t.IsArray) { - if (!reader.Read () || !reader.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 ++) diff --git a/csharp/msgpack/msgpack.csproj b/csharp/msgpack/msgpack.csproj index 1a778ae..2ecda11 100644 --- a/csharp/msgpack/msgpack.csproj +++ b/csharp/msgpack/msgpack.csproj @@ -1,4 +1,4 @@ - + Debug @@ -22,6 +22,7 @@ DEBUG;TRACE prompt 4 + true pdbonly @@ -30,6 +31,7 @@ TRACE prompt 4 + true @@ -38,6 +40,11 @@ + + + + + From 94e5b0d78fab7bdb9dadd4b5a31a81252ae57cf2 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sun, 17 Apr 2011 00:33:37 +0900 Subject: [PATCH 10/12] csharp: fix char pack/unpack problem on Mono --- csharp/msgpack/MsgPackWriter.cs | 5 +++++ csharp/msgpack/ObjectPacker.cs | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/csharp/msgpack/MsgPackWriter.cs b/csharp/msgpack/MsgPackWriter.cs index 78e347b..2bd3929 100644 --- a/csharp/msgpack/MsgPackWriter.cs +++ b/csharp/msgpack/MsgPackWriter.cs @@ -42,6 +42,11 @@ namespace msgpack } } + public void Write (char x) + { + Write ((ushort)x); + } + public void Write (uint x) { if (x < 0x10000) { diff --git a/csharp/msgpack/ObjectPacker.cs b/csharp/msgpack/ObjectPacker.cs index 0dabd21..fb0a7bf 100644 --- a/csharp/msgpack/ObjectPacker.cs +++ b/csharp/msgpack/ObjectPacker.cs @@ -61,7 +61,8 @@ namespace msgpack 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)) || t.Equals (typeof (char))) writer.Write ((ushort)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; } @@ -113,6 +114,26 @@ namespace msgpack 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) { From 33498d367323386942bef28a413aec8f1be0f7ef Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sat, 23 Apr 2011 14:14:12 +0900 Subject: [PATCH 11/12] csharp: Refactoring IL code generator & add two compiled packer implementation (dynamic-method, method-builder) --- csharp/msgpack.sln | 1 - csharp/msgpack.tests/CompiledPackerTests.cs | 37 +- csharp/msgpack/AssemblyInfo.cs | 1 + csharp/msgpack/CompiledPacker.cs | 499 ++++++++++++++- csharp/msgpack/Compiler/PackILGenerator.cs | 370 +++++++++++ csharp/msgpack/Compiler/PackerCompiler.cs | 643 -------------------- csharp/msgpack/msgpack.csproj | 2 +- 7 files changed, 883 insertions(+), 670 deletions(-) create mode 100644 csharp/msgpack/Compiler/PackILGenerator.cs delete mode 100644 csharp/msgpack/Compiler/PackerCompiler.cs diff --git a/csharp/msgpack.sln b/csharp/msgpack.sln index 351c7b8..2aad441 100644 --- a/csharp/msgpack.sln +++ b/csharp/msgpack.sln @@ -18,7 +18,6 @@ Global {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Debug|Any CPU.Build.0 = Debug|Any CPU {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE24167B-8F0A-4670-BD1E-3C283311E86B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/csharp/msgpack.tests/CompiledPackerTests.cs b/csharp/msgpack.tests/CompiledPackerTests.cs index 8e5a516..583409e 100644 --- a/csharp/msgpack.tests/CompiledPackerTests.cs +++ b/csharp/msgpack.tests/CompiledPackerTests.cs @@ -9,19 +9,44 @@ namespace msgpack.tests [TestFixture] public class CompiledPackerTests { + CompiledPacker _mbImpl = new CompiledPacker (false); + CompiledPacker _dynImpl = new CompiledPacker (true); + [Test] - public void TestA () + public void TestA_MethodBuilder () { - TestA_Class obj0 = new TestA_Class (); - TestA_Class obj1 = CompiledPacker.Unpack (CompiledPacker.Pack (obj0)); - obj0.Check (obj1); + TestA (_mbImpl); } [Test] - public void TestB () + public void TestA_DynamicMethod () + { + TestA (_dynImpl); + } + + [Test] + public void TestB_MethodBuilder () + { + TestB (_mbImpl); + } + + [Test] + public void TestB_DynamicMethod () + { + TestB (_dynImpl); + } + + void TestA (CompiledPacker packer) + { + TestA_Class obj0 = new TestA_Class (); + TestA_Class obj1 = packer.Unpack (packer.Pack (obj0)); + obj0.Check (obj1); + } + + void TestB (CompiledPacker packer) { TestB_Class obj0 = TestB_Class.Create (); - TestB_Class obj1 = CompiledPacker.Unpack (CompiledPacker.Pack (obj0)); + TestB_Class obj1 = packer.Unpack (packer.Pack (obj0)); obj0.Check (obj1); } } diff --git a/csharp/msgpack/AssemblyInfo.cs b/csharp/msgpack/AssemblyInfo.cs index 0ef2ef9..323742f 100644 --- a/csharp/msgpack/AssemblyInfo.cs +++ b/csharp/msgpack/AssemblyInfo.cs @@ -34,3 +34,4 @@ using System.Runtime.InteropServices; // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion ("1.0.0.0")] [assembly: AssemblyFileVersion ("1.0.0.0")] +[assembly: InternalsVisibleTo (msgpack.CompiledPacker.MethodBuilderPacker.AssemblyName)] diff --git a/csharp/msgpack/CompiledPacker.cs b/csharp/msgpack/CompiledPacker.cs index 7bb6b62..7245d1b 100644 --- a/csharp/msgpack/CompiledPacker.cs +++ b/csharp/msgpack/CompiledPacker.cs @@ -1,28 +1,38 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; +using System.Reflection; +using System.Reflection.Emit; +using System.Threading; using msgpack.Compiler; namespace msgpack { public class CompiledPacker { - public static byte[] Pack (object o) + static PackerBase _publicFieldPacker, _allFieldPacker; + PackerBase _packer; + + static CompiledPacker () { - using (MemoryStream ms = new MemoryStream ()) { - Pack (ms, o); - return ms.ToArray (); - } + _publicFieldPacker = new MethodBuilderPacker (); + _allFieldPacker = new DynamicMethodPacker (); } - public static void Pack (Stream strm, object o) + public CompiledPacker () : this (false) {} + public CompiledPacker (bool packPrivateField) { - PackerCompiler.GetPackMethod (o.GetType ()) (new MsgPackWriter (strm), o); + _packer = (packPrivateField ? _allFieldPacker : _publicFieldPacker); } - public static byte[] Pack (T o) + public void Prepare () + { + _packer.CreatePacker (); + _packer.CreateUnpacker (); + } + + #region Generics Pack/Unpack Methods + public byte[] Pack (T o) { using (MemoryStream ms = new MemoryStream ()) { Pack (ms, o); @@ -30,43 +40,494 @@ namespace msgpack } } - public static void Pack (Stream strm, T o) + public void Pack (Stream strm, T o) { - PackerCompiler.GetPackMethod () (new MsgPackWriter (strm), o); + _packer.CreatePacker () (new MsgPackWriter (strm), o); } - public static T Unpack (byte[] buf) + public T Unpack (byte[] buf) { return Unpack (buf, 0, buf.Length); } - public static T Unpack (byte[] buf, int offset, int size) + public T Unpack (byte[] buf, int offset, int size) { using (MemoryStream ms = new MemoryStream (buf, offset, size)) { return Unpack (ms); } } - public static T Unpack (Stream strm) + public T Unpack (Stream strm) { - return PackerCompiler.GetUnpackMethod () (new MsgPackReader (strm)); + return _packer.CreateUnpacker () (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 static object Unpack (Type t, byte[] buf) + 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 static object Unpack (Type t, byte[] buf, int offset, int size) + public object Unpack (Type t, byte[] buf, int offset, int size) { using (MemoryStream ms = new MemoryStream (buf, offset, size)) { return Unpack (t, ms); } } - public static object Unpack (Type t, Stream strm) + public object Unpack (Type t, Stream strm) { throw new NotImplementedException (); } + #endregion + + #region Compiled Packer Implementations + public abstract class PackerBase + { + Dictionary _packers = new Dictionary (); + Dictionary _unpackers = new Dictionary (); + + protected Dictionary _packMethods = new Dictionary (); + protected Dictionary _unpackMethods = new Dictionary (); + + protected PackerBase () + { + DefaultPackMethods.Register (_packMethods, _unpackMethods); + } + + public Action CreatePacker () + { + Delegate d; + lock (_packers) { + if (!_packers.TryGetValue (typeof (T), out d)) { + d = CreatePacker_Internal (); + _packers.Add (typeof (T), d); + } + } + return (Action)d; + } + + public Func CreateUnpacker () + { + Delegate d; + lock (_unpackers) { + if (!_unpackers.TryGetValue (typeof (T), out d)) { + d = CreateUnpacker_Internal (); + _unpackers.Add (typeof (T), d); + } + } + return (Func)d; + } + + protected abstract Action CreatePacker_Internal (); + protected abstract Func CreateUnpacker_Internal (); + } + public sealed class DynamicMethodPacker : PackerBase + { + protected static MethodInfo LookupMemberMappingMethod; + static Dictionary> UnpackMemberMappings; + + static DynamicMethodPacker () + { + UnpackMemberMappings = new Dictionary> (); + LookupMemberMappingMethod = typeof (DynamicMethodPacker).GetMethod ("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic); + } + + public DynamicMethodPacker () : base () + { + } + + protected override Action CreatePacker_Internal () + { + DynamicMethod dm = CreatePacker (typeof (T), CreatePackDynamicMethod (typeof (T))); + return (Action)dm.CreateDelegate (typeof (Action)); + } + + protected override Func CreateUnpacker_Internal () + { + DynamicMethod dm = CreateUnpacker (typeof (T), CreateUnpackDynamicMethod (typeof (T))); + return (Func)dm.CreateDelegate (typeof (Func)); + } + + 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 list = new List (); + 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 (\<.+\>) + 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 LookupMemberMapping (Type t) + { + IDictionary mapping; + lock (UnpackMemberMappings) { + if (!UnpackMemberMappings.TryGetValue (t, out mapping)) { + mapping = new Dictionary (); + 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; + + protected static MethodInfo LookupMemberMappingMethod; + static Dictionary> UnpackMemberMappings; + + static MethodBuilderPacker () + { + UnpackMemberMappings = new Dictionary> (); + 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 CreatePacker_Internal () + { + 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)Delegate.CreateDelegate (typeof (Action), mi); + } + + protected override Func CreateUnpacker_Internal () + { + 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)Delegate.CreateDelegate (typeof (Func), 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 list = new List (); + 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 LookupMemberMapping (Type t) + { + IDictionary mapping; + lock (UnpackMemberMappings) { + if (!UnpackMemberMappings.TryGetValue (t, out mapping)) { + mapping = new Dictionary (); + UnpackMemberMappings.Add (t, mapping); + } + } + return mapping; + } + } + #endregion + + #region default pack/unpack methods + internal static class DefaultPackMethods + { + public static void Register (Dictionary packMethods, Dictionary unpackMethods) + { + RegisterPackMethods (packMethods); + RegisterUnpackMethods (unpackMethods); + } + + #region Pack + static void RegisterPackMethods (Dictionary 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 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 } } diff --git a/csharp/msgpack/Compiler/PackILGenerator.cs b/csharp/msgpack/Compiler/PackILGenerator.cs new file mode 100644 index 0000000..d413acb --- /dev/null +++ b/csharp/msgpack/Compiler/PackILGenerator.cs @@ -0,0 +1,370 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.Serialization; + +namespace msgpack.Compiler +{ + static class PackILGenerator + { + #region Pack IL Generator + public static void EmitPackCode (Type type, MethodInfo mi, ILGenerator il, + Func targetMemberSelector, + Func memberNameFormatter, + Func 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 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); + } + + /// (optional) + /// (optional) + static void EmitPackMemberValueCode (Type type, ILGenerator il, Variable var_writer, Variable var_obj, + MemberInfo m, Variable elementIdx, Type currentType, MethodInfo currentMethod, Func 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 targetMemberSelector, + Func memberNameFormatter, + Func lookupUnpackMethod, + Func> 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 targetMemberSelector, + Func memberNameFormatter, + Func lookupUnpackMethod, + Func> lookupMemberMapping, + MethodInfo lookupMemberMappingMethod) + { + MethodInfo failedMethod = typeof (PackILGenerator).GetMethod ("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic); + MemberInfo[] members = targetMemberSelector (type); + IDictionary 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))); + 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).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 targetMemberSelector, + Func memberNameFormatter, + Func 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); + } + + /// Exception Helper + 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 + } +} diff --git a/csharp/msgpack/Compiler/PackerCompiler.cs b/csharp/msgpack/Compiler/PackerCompiler.cs deleted file mode 100644 index 0776717..0000000 --- a/csharp/msgpack/Compiler/PackerCompiler.cs +++ /dev/null @@ -1,643 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using System.Reflection.Emit; -using System.Threading; -using System.Runtime.Serialization; - -namespace msgpack.Compiler -{ - public static class PackerCompiler - { - static Dictionary CompiledPackMethods; - static Dictionary PackDelegates; - static Dictionary> PackWrapperDelegates; - - static Dictionary CompiledUnpackMethods; - static Dictionary UnpackDelegates; - static Dictionary> UnpackFieldMapping; - - static Dictionary UserDefinedPackMethods; - - static PackerCompiler () - { - CompiledPackMethods = new Dictionary (); - PackDelegates = new Dictionary (); - PackWrapperDelegates = new Dictionary> (); - UserDefinedPackMethods = new Dictionary (); - - CompiledUnpackMethods = new Dictionary (); - UnpackDelegates = new Dictionary (); - UnpackFieldMapping = new Dictionary> (); - - RegisterDefaultUnpackMethods (); - RegisterUserDefinedMethods (); - } - - #region Pack Frontend / Compiler - public static Action GetPackMethod () - { - Delegate d; - lock (CompiledPackMethods) { - PackDelegates.TryGetValue (typeof (T), out d); - } - if (d == null) - CreatePackMethod (typeof (T)); - lock (CompiledPackMethods) { - d = PackDelegates[typeof (T)]; - } - return (Action)d; - } - - public static Action GetPackMethod (Type t) - { - Action d; - lock (CompiledPackMethods) { - PackWrapperDelegates.TryGetValue (t, out d); - } - if (d == null) - CreatePackMethod (t); - lock (CompiledPackMethods) { - d = PackWrapperDelegates[t]; - } - return d; - } - - static DynamicMethod CreatePackMethod (Type t) - { - DynamicMethod methodBuilder; - lock (CompiledPackMethods) { - if (CompiledPackMethods.TryGetValue (t, out methodBuilder)) { - return CompiledPackMethods[t]; - } else { - methodBuilder = CreateDynamicMethod (typeof (void), new Type[]{typeof (MsgPackWriter), t}); - CompiledPackMethods.Add (t, methodBuilder); - CreatePackMethod (t, methodBuilder); - PackDelegates.Add (t, methodBuilder.CreateDelegate (typeof (Action<,>).MakeGenericType (typeof (MsgPackWriter), t))); - Action wrapper = CreatePackWrapper (t, methodBuilder); - PackWrapperDelegates.Add (t, wrapper); - } - } - return methodBuilder; - } - - static void CreatePackMethod (Type t, DynamicMethod methodBuilder) - { - if (t == null || methodBuilder == null) - throw new ArgumentNullException (); - if (t.IsPrimitive || t.IsInterface) - throw new NotSupportedException (); - - ILGenerator il = methodBuilder.GetILGenerator(); - - Variable arg_writer = Variable.CreateArg (0); - Variable arg_obj = Variable.CreateArg (1); - Variable local_i = Variable.CreateLocal (il.DeclareLocal (typeof (int))); - - if (!t.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); - } - - MethodInfo udm; - lock (UserDefinedPackMethods) { - UserDefinedPackMethods.TryGetValue (t, out udm); - } - if (udm != null) { - il.EmitLd (arg_writer, arg_obj); - il.Emit (OpCodes.Call, udm); - goto FinallyProcess; - } - - if (t.IsArray) { - EmitArrayWriteProcess (il, t, arg_writer, arg_obj, local_i); - goto FinallyProcess; - } - - // MsgPackWriter.WriteMapHeader - MemberInfo[] members = LookupMembers (t); - 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 (FormatMemberName (m)); - il.EmitLd_True (); - il.Emit (OpCodes.Call, typeof (MsgPackWriter).GetMethod("Write", new Type[]{typeof (string), typeof (bool)})); - - // write value - CreatePackMethod_EmitMemberValue (il, arg_writer, arg_obj, m, null, mt, t, methodBuilder); - } - -FinallyProcess: - il.Emit (OpCodes.Ret); - } - - static void EmitArrayWriteProcess (ILGenerator il, Type t, Variable var_writer, Variable var_obj, Variable var_loop) - { - 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 - CreatePackMethod_EmitMemberValue (il, var_writer, var_obj, null, var_loop, et, null, null); - - // 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); - } - - /// (optional) - /// (optional) - static void CreatePackMethod_EmitMemberValue (ILGenerator il, Variable var_writer, Variable var_obj, MemberInfo m, Variable elementIdx, Type type, Type currentType, DynamicMethod currentMethod) - { - 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 { - lock (UserDefinedPackMethods) { - UserDefinedPackMethods.TryGetValue (type, out mi); - } - if (mi == null) - mi = CreatePackMethod (type); - } - } - il.Emit (OpCodes.Call, mi); - } - - static Action CreatePackWrapper (Type t, DynamicMethod packMethod) - { - DynamicMethod dm = CreateDynamicMethod (typeof (void), new Type[] {typeof (MsgPackWriter), typeof (object)}); - ILGenerator il = dm.GetILGenerator(); - il.EmitLd (Variable.CreateArg (0), Variable.CreateArg (1)); - il.Emit (OpCodes.Castclass, t); - il.Emit (OpCodes.Call, packMethod); - il.Emit (OpCodes.Ret); - return (Action)dm.CreateDelegate (typeof (Action)); - } - #endregion - - #region Unpack Frontend / Compiler - public static Func GetUnpackMethod () - { - Delegate d; - lock (CompiledUnpackMethods) { - UnpackDelegates.TryGetValue (typeof (T), out d); - } - if (d == null) - CreateUnpackMethod (typeof (T)); - lock (CompiledUnpackMethods) { - d = UnpackDelegates[typeof (T)]; - } - return (Func)d; - } - - static MethodInfo CreateUnpackMethod (Type t) - { - MethodInfo methodBuilder; - lock (CompiledUnpackMethods) { - if (CompiledUnpackMethods.TryGetValue (t, out methodBuilder)) { - return methodBuilder; - } else { - methodBuilder = CreateDynamicMethod (t, new Type[]{typeof (MsgPackReader)}); - CompiledUnpackMethods.Add (t, methodBuilder); - UnpackFieldMapping.Add (t, new Dictionary ()); - if (t.IsArray) { - CreateUnpackArrayMethod (t, t.GetElementType (), (DynamicMethod)methodBuilder); - } else { - CreateUnpackMethod (t, (DynamicMethod)methodBuilder); - } - UnpackDelegates.Add (t, ((DynamicMethod)methodBuilder).CreateDelegate (typeof (Func<,>).MakeGenericType (typeof (MsgPackReader), t))); - } - } - return methodBuilder; - } - - static void CreateUnpackMethod (Type t, DynamicMethod methodBuilder) - { - ILGenerator il = methodBuilder.GetILGenerator (); - MethodInfo failedMethod = typeof (PackerCompiler).GetMethod ("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic); - MemberInfo[] members = LookupMembers (t); - Dictionary member_mapping = UnpackFieldMapping[t]; - for (int i = 0; i < members.Length; i ++) - member_mapping.Add (FormatMemberName (members[i]), i); - - Variable msgpackReader = Variable.CreateArg (0); - Variable obj = Variable.CreateLocal (il.DeclareLocal (t)); - 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 (Dictionary))); - Variable switch_idx = Variable.CreateLocal (il.DeclareLocal (typeof (int))); - Variable type = Variable.CreateLocal (il.DeclareLocal (typeof (Type))); - - // if (!MsgPackReader.Read()) UnpackFailed (); - // if (MsgPackReader.Type == TypePrefixes.Nil) return null; - // if (!MsgPackReader.IsMap ()) UnpackFailed (); - EmitReadAndTypeCheck (il, msgpackReader, typeof (MsgPackReader).GetMethod ("IsMap"), failedMethod, true); - - // type = typeof (T) - il.Emit (OpCodes.Ldtoken, t); - il.Emit (OpCodes.Call, typeof(Type).GetMethod ("GetTypeFromHandle")); - il.EmitSt (type); - - // mapping = LookupMemberMapping (typeof (T)) - il.EmitLd (type); - il.Emit (OpCodes.Call, typeof (PackerCompiler).GetMethod ("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic)); - il.EmitSt (mapping); - - // object o = FormatterServices.GetUninitializedObject (Type); - il.EmitLd (type); - il.Emit (OpCodes.Call, typeof (FormatterServices).GetMethod ("GetUninitializedObject")); - il.Emit (OpCodes.Castclass, t); - 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(); - EmitReadAndTypeCheck (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, (short)switch_idx.Index); - il.Emit (OpCodes.Call, typeof (Dictionary).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 mi = members[i]; - Type mt = mi.GetMemberType (); - MethodInfo unpack_method; - - il.EmitLd (obj); - if (!CompiledUnpackMethods.TryGetValue (mt, out unpack_method)) { - unpack_method = CreateUnpackMethod (mt); - } - il.EmitLd (msgpackReader); - il.Emit (OpCodes.Call, unpack_method); - il.EmitStMember (mi); - 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 CreateUnpackArrayMethod (Type arrayType, Type elementType, DynamicMethod methodBuilder) - { - ILGenerator il = methodBuilder.GetILGenerator (); - MethodInfo failedMethod = typeof (PackerCompiler).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 (); - EmitReadAndTypeCheck (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; - lock (CompiledUnpackMethods) { - if (!CompiledUnpackMethods.TryGetValue (elementType, out unpack_method)) { - unpack_method = CreateUnpackMethod (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 EmitReadAndTypeCheck (ILGenerator il, Variable msgpackReader, MethodInfo typeCheckMethod, MethodInfo failedMethod, bool nullCheckAndReturn) - { - Label lblFailed = il.DefineLabel (); - Label lblNullReturn = il.DefineLabel (); - 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); - if (nullCheckAndReturn) { - il.MarkLabel (lblNullReturn); - il.Emit (OpCodes.Ldnull); - il.Emit (OpCodes.Ret); - } - il.MarkLabel (lblFailed); - il.Emit (OpCodes.Call, failedMethod); - il.MarkLabel (lblPassed); - } - - /// Exception Helper - static void UnpackFailed () - { - throw new FormatException (); - } - - static Dictionary LookupMemberMapping (Type t) - { - lock (CompiledUnpackMethods) { - return UnpackFieldMapping[t]; - } - } - - static void RegisterDefaultUnpackMethods () - { - BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; - MethodInfo mi = typeof (PackerCompiler).GetMethod ("Unpack_Signed", flags); - CompiledUnpackMethods.Add (typeof (sbyte), mi); - CompiledUnpackMethods.Add (typeof (short), mi); - CompiledUnpackMethods.Add (typeof (int), mi); - - mi = typeof (PackerCompiler).GetMethod ("Unpack_Signed64", flags); - CompiledUnpackMethods.Add (typeof (long), mi); - - mi = typeof (PackerCompiler).GetMethod ("Unpack_Unsigned", flags); - CompiledUnpackMethods.Add (typeof (byte), mi); - CompiledUnpackMethods.Add (typeof (ushort), mi); - CompiledUnpackMethods.Add (typeof (char), mi); - CompiledUnpackMethods.Add (typeof (uint), mi); - - mi = typeof (PackerCompiler).GetMethod ("Unpack_Unsigned64", flags); - CompiledUnpackMethods.Add (typeof (ulong), mi); - - mi = typeof (PackerCompiler).GetMethod ("Unpack_Boolean", flags); - CompiledUnpackMethods.Add (typeof (bool), mi); - - mi = typeof (PackerCompiler).GetMethod ("Unpack_Float", flags); - CompiledUnpackMethods.Add (typeof (float), mi); - - mi = typeof (PackerCompiler).GetMethod ("Unpack_Double", flags); - CompiledUnpackMethods.Add (typeof (double), mi); - - mi = typeof (PackerCompiler).GetMethod ("Unpack_String", flags); - CompiledUnpackMethods.Add (typeof (string), mi); - } - - static int Unpack_Signed (MsgPackReader reader) - { - if (!reader.Read () || !reader.IsSigned ()) - UnpackFailed (); - return reader.ValueSigned; - } - - 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 - } - - static uint Unpack_Unsigned (MsgPackReader reader) - { - if (!reader.Read () || !reader.IsUnsigned ()) - UnpackFailed (); - return reader.ValueUnsigned; - } - - 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 - } - - static bool Unpack_Boolean (MsgPackReader reader) - { - if (!reader.Read () || !reader.IsBoolean ()) - UnpackFailed (); - return reader.ValueBoolean; - } - - static float Unpack_Float (MsgPackReader reader) - { - if (!reader.Read () || reader.Type != TypePrefixes.Float) - UnpackFailed (); - return reader.ValueFloat; - } - - static double Unpack_Double (MsgPackReader reader) - { - if (!reader.Read () || reader.Type != TypePrefixes.Double) - UnpackFailed (); - return reader.ValueDouble; - } - - static string Unpack_String (MsgPackReader reader) - { - if (!reader.Read () || !reader.IsRaw ()) - UnpackFailed (); - return reader.ReadRawString (); - } - #endregion - - #region User Defined Packer/Unpackers - static void RegisterUserDefinedMethods () - { - BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; - Type type = typeof (PackerCompiler); - object[][] list = new object[][] { - new object[] {typeof (string), "PackString"} - }; - for (int i = 0; i < list.Length; i ++) - UserDefinedPackMethods.Add ((Type)list[i][0], type.GetMethod ((string)list[i][1], flags)); - } - - static void PackString (MsgPackWriter writer, string x) - { - writer.Write (x); - } - #endregion - - #region Misc - 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); - } - - static MemberInfo[] LookupMembers (Type t) - { - BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - List list = new List (); - list.AddRange (t.GetFields (baseFlags)); - //list.AddRange (t.GetProperties (baseFlags)); // TODO: - return list.ToArray (); - } - - 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 (\<.+\>) - return name; - } - - 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 - } -} diff --git a/csharp/msgpack/msgpack.csproj b/csharp/msgpack/msgpack.csproj index 2ecda11..086b729 100644 --- a/csharp/msgpack/msgpack.csproj +++ b/csharp/msgpack/msgpack.csproj @@ -42,7 +42,7 @@ - + From 6cfea98501e3f56b0c8fbe29334d4a49b1fd57c3 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sat, 23 Apr 2011 14:44:22 +0900 Subject: [PATCH 12/12] csharp: add license, rename filename/namespace. --- .gitignore | 14 +++--- csharp/Makefile | 14 +++--- csharp/MsgPack.Test/AssemblyInfo.cs | 26 ++++++++++ .../BoxingPackerTests.cs | 20 +++++++- .../CompiledPackerTests.cs | 26 +++++++--- .../MsgPack.Test.csproj} | 8 ++-- .../ObjectPackerTests.cs | 21 ++++++-- .../ReaderWriterTests.cs | 20 +++++++- csharp/{msgpack.sln => MsgPack.sln} | 4 +- csharp/MsgPack/AssemblyInfo.cs | 28 +++++++++++ csharp/{msgpack => MsgPack}/BoxingPacker.cs | 20 +++++++- csharp/{msgpack => MsgPack}/CompiledPacker.cs | 22 +++++++-- .../Compiler/EmitExtensions.cs | 23 +++++++-- .../Compiler/PackILGenerator.cs | 20 +++++++- csharp/MsgPack/Compiler/Variable.cs | 42 ++++++++++++++++ csharp/MsgPack/Compiler/VariableType.cs | 24 ++++++++++ .../msgpack.csproj => MsgPack/MsgPack.csproj} | 4 +- csharp/{msgpack => MsgPack}/MsgPackReader.cs | 20 +++++++- csharp/{msgpack => MsgPack}/MsgPackWriter.cs | 20 +++++++- csharp/{msgpack => MsgPack}/ObjectPacker.cs | 20 +++++++- .../{msgpack => MsgPack}/ReflectionCache.cs | 20 +++++++- .../ReflectionCacheEntry.cs | 20 +++++++- csharp/MsgPack/TypePrefixes.cs | 48 +++++++++++++++++++ csharp/msgpack.tests/AssemblyInfo.cs | 36 -------------- csharp/msgpack/AssemblyInfo.cs | 37 -------------- csharp/msgpack/Compiler/Variable.cs | 30 ------------ csharp/msgpack/Compiler/VariableType.cs | 13 ----- csharp/msgpack/TypePrefixes.cs | 32 ------------- 28 files changed, 427 insertions(+), 205 deletions(-) create mode 100644 csharp/MsgPack.Test/AssemblyInfo.cs rename csharp/{msgpack.tests => MsgPack.Test}/BoxingPackerTests.cs (76%) rename csharp/{msgpack.tests => MsgPack.Test}/CompiledPackerTests.cs (54%) rename csharp/{msgpack.tests/msgpack.tests.csproj => MsgPack.Test/MsgPack.Test.csproj} (93%) rename csharp/{msgpack.tests => MsgPack.Test}/ObjectPackerTests.cs (80%) rename csharp/{msgpack.tests => MsgPack.Test}/ReaderWriterTests.cs (92%) rename csharp/{msgpack.sln => MsgPack.sln} (78%) create mode 100644 csharp/MsgPack/AssemblyInfo.cs rename csharp/{msgpack => MsgPack}/BoxingPacker.cs (87%) rename csharp/{msgpack => MsgPack}/CompiledPacker.cs (95%) rename csharp/{msgpack => MsgPack}/Compiler/EmitExtensions.cs (87%) rename csharp/{msgpack => MsgPack}/Compiler/PackILGenerator.cs (95%) create mode 100644 csharp/MsgPack/Compiler/Variable.cs create mode 100644 csharp/MsgPack/Compiler/VariableType.cs rename csharp/{msgpack/msgpack.csproj => MsgPack/MsgPack.csproj} (96%) rename csharp/{msgpack => MsgPack}/MsgPackReader.cs (91%) rename csharp/{msgpack => MsgPack}/MsgPackWriter.cs (90%) rename csharp/{msgpack => MsgPack}/ObjectPacker.cs (92%) rename csharp/{msgpack => MsgPack}/ReflectionCache.cs (53%) rename csharp/{msgpack => MsgPack}/ReflectionCacheEntry.cs (56%) create mode 100644 csharp/MsgPack/TypePrefixes.cs delete mode 100644 csharp/msgpack.tests/AssemblyInfo.cs delete mode 100644 csharp/msgpack/AssemblyInfo.cs delete mode 100644 csharp/msgpack/Compiler/Variable.cs delete mode 100644 csharp/msgpack/Compiler/VariableType.cs delete mode 100644 csharp/msgpack/TypePrefixes.cs diff --git a/.gitignore b/.gitignore index 45b7161..305f896 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,10 @@ ruby/Makefile *.6 _obj _test -/csharp/msgpack.suo -/csharp/msgpack/bin -/csharp/msgpack/obj -/csharp/msgpack/msgpack.csproj.user -/csharp/msgpack.tests/obj -/csharp/msgpack.tests/bin -/csharp/msgpack.tests/msgpack.tests.csproj.user +/csharp/MsgPack.suo +/csharp/MsgPack/bin +/csharp/MsgPack/obj +/csharp/MsgPack/MsgPack.csproj.user +/csharp/MsgPack.Test/obj +/csharp/MsgPack.Test/bin +/csharp/MsgPack.Test/MsgPack.Test.csproj.user diff --git a/csharp/Makefile b/csharp/Makefile index 4f89338..9cf6a24 100644 --- a/csharp/Makefile +++ b/csharp/Makefile @@ -1,8 +1,8 @@ -TARGET=msgpack.dll -TEST_TARGET=msgpack.tests.dll +TARGET=MsgPack.dll +TEST_TARGET=MsgPack.Test.dll -SRC=$(shell find msgpack -name "*.cs") -TEST_SRC=$(shell find msgpack.tests -name "*.cs") +SRC=$(shell find MsgPack -name "*.cs") +TEST_SRC=$(shell find MsgPack.Test -name "*.cs") MONO_CC=mcs NUNIT_CONSOLE=nunit-console @@ -15,7 +15,7 @@ run-test: $(NUNIT_CONSOLE) $(TEST_TARGET) $(TARGET): $(SRC) - $(MONO_CC) -out:$@ -t:library -unsafe+ $^ + $(MONO_CC) -out:$@ -t:library -unsafe+ $(SRC) -$(TEST_TARGET): $(TEST_SRC) - $(MONO_CC) -out:$@ -t:library -r:$(TARGET) -r:nunit.framework.dll $^ +$(TEST_TARGET): $(TEST_SRC) $(TARGET) + $(MONO_CC) -out:$@ -t:library -r:$(TARGET) -r:nunit.framework.dll $(TEST_SRC) diff --git a/csharp/MsgPack.Test/AssemblyInfo.cs b/csharp/MsgPack.Test/AssemblyInfo.cs new file mode 100644 index 0000000..307c6a9 --- /dev/null +++ b/csharp/MsgPack.Test/AssemblyInfo.cs @@ -0,0 +1,26 @@ +// +// 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; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("MsgPack UnitTest")] +[assembly: AssemblyProduct ("MsgPack UnitTest")] +[assembly: AssemblyDescription ("MessagePack Serializer for .NET UnitTests")] +[assembly: AssemblyCopyright ("Copyright © 2011 Kazuki Oikawa")] + +[assembly: ComVisible (false)] +[assembly: AssemblyVersion ("0.1.*")] diff --git a/csharp/msgpack.tests/BoxingPackerTests.cs b/csharp/MsgPack.Test/BoxingPackerTests.cs similarity index 76% rename from csharp/msgpack.tests/BoxingPackerTests.cs rename to csharp/MsgPack.Test/BoxingPackerTests.cs index cd63129..a39a3c8 100644 --- a/csharp/msgpack.tests/BoxingPackerTests.cs +++ b/csharp/MsgPack.Test/BoxingPackerTests.cs @@ -1,9 +1,25 @@ -using System; +// +// 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.Linq; using NUnit.Framework; -namespace msgpack.tests +namespace MsgPack.Test { [TestFixture] public class BoxingPackerTests diff --git a/csharp/msgpack.tests/CompiledPackerTests.cs b/csharp/MsgPack.Test/CompiledPackerTests.cs similarity index 54% rename from csharp/msgpack.tests/CompiledPackerTests.cs rename to csharp/MsgPack.Test/CompiledPackerTests.cs index 583409e..16daef9 100644 --- a/csharp/msgpack.tests/CompiledPackerTests.cs +++ b/csharp/MsgPack.Test/CompiledPackerTests.cs @@ -1,10 +1,24 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using TestA_Class = msgpack.tests.ObjectPackerTests.TestA_Class; -using TestB_Class = msgpack.tests.ObjectPackerTests.TestB_Class; +// +// 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. +// -namespace msgpack.tests +using NUnit.Framework; +using TestA_Class = MsgPack.Test.ObjectPackerTests.TestA_Class; +using TestB_Class = MsgPack.Test.ObjectPackerTests.TestB_Class; + +namespace MsgPack.Test { [TestFixture] public class CompiledPackerTests diff --git a/csharp/msgpack.tests/msgpack.tests.csproj b/csharp/MsgPack.Test/MsgPack.Test.csproj similarity index 93% rename from csharp/msgpack.tests/msgpack.tests.csproj rename to csharp/MsgPack.Test/MsgPack.Test.csproj index 1991021..e00c3cc 100644 --- a/csharp/msgpack.tests/msgpack.tests.csproj +++ b/csharp/MsgPack.Test/MsgPack.Test.csproj @@ -8,8 +8,8 @@ {CE24167B-8F0A-4670-BD1E-3C283311E86B} Library Properties - msgpack.tests - msgpack.tests + MsgPack.Test + MsgPack.Test v4.0 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -49,9 +49,9 @@ - + {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F} - msgpack + MsgPack diff --git a/csharp/msgpack.tests/ObjectPackerTests.cs b/csharp/MsgPack.Test/ObjectPackerTests.cs similarity index 80% rename from csharp/msgpack.tests/ObjectPackerTests.cs rename to csharp/MsgPack.Test/ObjectPackerTests.cs index 70ec9e0..26f3d3b 100644 --- a/csharp/msgpack.tests/ObjectPackerTests.cs +++ b/csharp/MsgPack.Test/ObjectPackerTests.cs @@ -1,8 +1,23 @@ -using System; -using System.Collections.Generic; +// +// 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 NUnit.Framework; -namespace msgpack.tests +namespace MsgPack.Test { [TestFixture] public class ObjectPackerTests diff --git a/csharp/msgpack.tests/ReaderWriterTests.cs b/csharp/MsgPack.Test/ReaderWriterTests.cs similarity index 92% rename from csharp/msgpack.tests/ReaderWriterTests.cs rename to csharp/MsgPack.Test/ReaderWriterTests.cs index 10c6f70..5971285 100644 --- a/csharp/msgpack.tests/ReaderWriterTests.cs +++ b/csharp/MsgPack.Test/ReaderWriterTests.cs @@ -1,8 +1,24 @@ -using System; +// +// 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 NUnit.Framework; -namespace msgpack.tests +namespace MsgPack.Test { [TestFixture] public class ReaderWriterTests diff --git a/csharp/msgpack.sln b/csharp/MsgPack.sln similarity index 78% rename from csharp/msgpack.sln rename to csharp/MsgPack.sln index 2aad441..3cdebef 100644 --- a/csharp/msgpack.sln +++ b/csharp/MsgPack.sln @@ -1,9 +1,9 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "msgpack", "msgpack\msgpack.csproj", "{E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsgPack", "MsgPack\MsgPack.csproj", "{E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "msgpack.tests", "msgpack.tests\msgpack.tests.csproj", "{CE24167B-8F0A-4670-BD1E-3C283311E86B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsgPack.Test", "MsgPack.Test/MsgPack.Test.csproj", "{CE24167B-8F0A-4670-BD1E-3C283311E86B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/csharp/MsgPack/AssemblyInfo.cs b/csharp/MsgPack/AssemblyInfo.cs new file mode 100644 index 0000000..27f8837 --- /dev/null +++ b/csharp/MsgPack/AssemblyInfo.cs @@ -0,0 +1,28 @@ +// +// 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; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle ("MsgPack")] +[assembly: AssemblyProduct ("MsgPack")] +[assembly: AssemblyDescription ("MessagePack Serializer for .NET")] +[assembly: AssemblyCopyright ("Copyright © 2011 Kazuki Oikawa")] + +[assembly: ComVisible (false)] +[assembly: AssemblyVersion ("0.1.*")] +[assembly: InternalsVisibleTo (MsgPack.CompiledPacker.MethodBuilderPacker.AssemblyName)] diff --git a/csharp/msgpack/BoxingPacker.cs b/csharp/MsgPack/BoxingPacker.cs similarity index 87% rename from csharp/msgpack/BoxingPacker.cs rename to csharp/MsgPack/BoxingPacker.cs index c460850..0546683 100644 --- a/csharp/msgpack/BoxingPacker.cs +++ b/csharp/MsgPack/BoxingPacker.cs @@ -1,10 +1,26 @@ -using System; +// +// 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; -namespace msgpack +namespace MsgPack { public class BoxingPacker { diff --git a/csharp/msgpack/CompiledPacker.cs b/csharp/MsgPack/CompiledPacker.cs similarity index 95% rename from csharp/msgpack/CompiledPacker.cs rename to csharp/MsgPack/CompiledPacker.cs index 7245d1b..1d4b747 100644 --- a/csharp/msgpack/CompiledPacker.cs +++ b/csharp/MsgPack/CompiledPacker.cs @@ -1,12 +1,28 @@ -using System; +// +// 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; +using MsgPack.Compiler; -namespace msgpack +namespace MsgPack { public class CompiledPacker { diff --git a/csharp/msgpack/Compiler/EmitExtensions.cs b/csharp/MsgPack/Compiler/EmitExtensions.cs similarity index 87% rename from csharp/msgpack/Compiler/EmitExtensions.cs rename to csharp/MsgPack/Compiler/EmitExtensions.cs index ae51e9a..794aff4 100644 --- a/csharp/msgpack/Compiler/EmitExtensions.cs +++ b/csharp/MsgPack/Compiler/EmitExtensions.cs @@ -1,11 +1,24 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// +// 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; -namespace msgpack.Compiler +namespace MsgPack.Compiler { public static class EmitExtensions { diff --git a/csharp/msgpack/Compiler/PackILGenerator.cs b/csharp/MsgPack/Compiler/PackILGenerator.cs similarity index 95% rename from csharp/msgpack/Compiler/PackILGenerator.cs rename to csharp/MsgPack/Compiler/PackILGenerator.cs index d413acb..1f116ad 100644 --- a/csharp/msgpack/Compiler/PackILGenerator.cs +++ b/csharp/MsgPack/Compiler/PackILGenerator.cs @@ -1,10 +1,26 @@ -using System; +// +// 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; -namespace msgpack.Compiler +namespace MsgPack.Compiler { static class PackILGenerator { diff --git a/csharp/MsgPack/Compiler/Variable.cs b/csharp/MsgPack/Compiler/Variable.cs new file mode 100644 index 0000000..00c8e51 --- /dev/null +++ b/csharp/MsgPack/Compiler/Variable.cs @@ -0,0 +1,42 @@ +// +// 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; + +namespace MsgPack.Compiler +{ + 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; } + } +} diff --git a/csharp/MsgPack/Compiler/VariableType.cs b/csharp/MsgPack/Compiler/VariableType.cs new file mode 100644 index 0000000..306b516 --- /dev/null +++ b/csharp/MsgPack/Compiler/VariableType.cs @@ -0,0 +1,24 @@ +// +// 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. +// + +namespace MsgPack.Compiler +{ + public enum VariableType + { + Local, + Arg + } +} diff --git a/csharp/msgpack/msgpack.csproj b/csharp/MsgPack/MsgPack.csproj similarity index 96% rename from csharp/msgpack/msgpack.csproj rename to csharp/MsgPack/MsgPack.csproj index 086b729..9a8d13d 100644 --- a/csharp/msgpack/msgpack.csproj +++ b/csharp/MsgPack/MsgPack.csproj @@ -8,8 +8,8 @@ {E1809531-EC2A-4EA6-B0E8-CC815EDFAA2F} Library Properties - msgpack - msgpack + MsgPack + MsgPack v4.0 512 Client diff --git a/csharp/msgpack/MsgPackReader.cs b/csharp/MsgPack/MsgPackReader.cs similarity index 91% rename from csharp/msgpack/MsgPackReader.cs rename to csharp/MsgPack/MsgPackReader.cs index 06a37e0..3338a53 100644 --- a/csharp/msgpack/MsgPackReader.cs +++ b/csharp/MsgPack/MsgPackReader.cs @@ -1,8 +1,24 @@ -using System; +// +// 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; -namespace msgpack +namespace MsgPack { public class MsgPackReader { diff --git a/csharp/msgpack/MsgPackWriter.cs b/csharp/MsgPack/MsgPackWriter.cs similarity index 90% rename from csharp/msgpack/MsgPackWriter.cs rename to csharp/MsgPack/MsgPackWriter.cs index 2bd3929..39647d8 100644 --- a/csharp/msgpack/MsgPackWriter.cs +++ b/csharp/MsgPack/MsgPackWriter.cs @@ -1,8 +1,24 @@ -using System; +// +// 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; -namespace msgpack +namespace MsgPack { public class MsgPackWriter { diff --git a/csharp/msgpack/ObjectPacker.cs b/csharp/MsgPack/ObjectPacker.cs similarity index 92% rename from csharp/msgpack/ObjectPacker.cs rename to csharp/MsgPack/ObjectPacker.cs index fb0a7bf..08f4796 100644 --- a/csharp/msgpack/ObjectPacker.cs +++ b/csharp/MsgPack/ObjectPacker.cs @@ -1,11 +1,27 @@ -using System; +// +// 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; -namespace msgpack +namespace MsgPack { public class ObjectPacker { diff --git a/csharp/msgpack/ReflectionCache.cs b/csharp/MsgPack/ReflectionCache.cs similarity index 53% rename from csharp/msgpack/ReflectionCache.cs rename to csharp/MsgPack/ReflectionCache.cs index d7f9726..34d46e7 100644 --- a/csharp/msgpack/ReflectionCache.cs +++ b/csharp/MsgPack/ReflectionCache.cs @@ -1,7 +1,23 @@ -using System; +// +// 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; -namespace msgpack +namespace MsgPack { public static class ReflectionCache { diff --git a/csharp/msgpack/ReflectionCacheEntry.cs b/csharp/MsgPack/ReflectionCacheEntry.cs similarity index 56% rename from csharp/msgpack/ReflectionCacheEntry.cs rename to csharp/MsgPack/ReflectionCacheEntry.cs index 9a27f70..bec4d4c 100644 --- a/csharp/msgpack/ReflectionCacheEntry.cs +++ b/csharp/MsgPack/ReflectionCacheEntry.cs @@ -1,8 +1,24 @@ -using System; +// +// 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; -namespace msgpack +namespace MsgPack { public class ReflectionCacheEntry { diff --git a/csharp/MsgPack/TypePrefixes.cs b/csharp/MsgPack/TypePrefixes.cs new file mode 100644 index 0000000..a7c97a6 --- /dev/null +++ b/csharp/MsgPack/TypePrefixes.cs @@ -0,0 +1,48 @@ +// +// 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. +// + +namespace MsgPack +{ + 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 + } +} diff --git a/csharp/msgpack.tests/AssemblyInfo.cs b/csharp/msgpack.tests/AssemblyInfo.cs deleted file mode 100644 index de7e181..0000000 --- a/csharp/msgpack.tests/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle ("msgpack.tests")] -[assembly: AssemblyDescription ("")] -[assembly: AssemblyConfiguration ("")] -[assembly: AssemblyCompany ("Microsoft")] -[assembly: AssemblyProduct ("msgpack.tests")] -[assembly: AssemblyCopyright ("Copyright © Microsoft 2011")] -[assembly: AssemblyTrademark ("")] -[assembly: AssemblyCulture ("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible (false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid ("82a4db7c-686b-4206-9cc9-9aae082d7e73")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.0.0.0")] -[assembly: AssemblyFileVersion ("1.0.0.0")] diff --git a/csharp/msgpack/AssemblyInfo.cs b/csharp/msgpack/AssemblyInfo.cs deleted file mode 100644 index 323742f..0000000 --- a/csharp/msgpack/AssemblyInfo.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle ("msgpack")] -[assembly: AssemblyDescription ("")] -[assembly: AssemblyConfiguration ("")] -[assembly: AssemblyCompany ("Microsoft")] -[assembly: AssemblyProduct ("msgpack")] -[assembly: AssemblyCopyright ("Copyright © Microsoft 2011")] -[assembly: AssemblyTrademark ("")] -[assembly: AssemblyCulture ("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible (false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid ("aae99974-7a7d-4787-83ca-614779d54bd2")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.0.0.0")] -[assembly: AssemblyFileVersion ("1.0.0.0")] -[assembly: InternalsVisibleTo (msgpack.CompiledPacker.MethodBuilderPacker.AssemblyName)] diff --git a/csharp/msgpack/Compiler/Variable.cs b/csharp/msgpack/Compiler/Variable.cs deleted file mode 100644 index bac3434..0000000 --- a/csharp/msgpack/Compiler/Variable.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection.Emit; - -namespace msgpack.Compiler -{ - 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; } - } -} diff --git a/csharp/msgpack/Compiler/VariableType.cs b/csharp/msgpack/Compiler/VariableType.cs deleted file mode 100644 index 9a0dbce..0000000 --- a/csharp/msgpack/Compiler/VariableType.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace msgpack.Compiler -{ - public enum VariableType - { - Local, - Arg - } -} diff --git a/csharp/msgpack/TypePrefixes.cs b/csharp/msgpack/TypePrefixes.cs deleted file mode 100644 index 633991b..0000000 --- a/csharp/msgpack/TypePrefixes.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace msgpack -{ - 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 - } -}