Consoletest/Program.cs | 31 ++-- Consoletest/consoletest.csproj | 1 - Consoletest/dataobjects.cs | 4 + fastJSON/JSON.cs | 338 ++++++++++++++++++++++++++--------------- fastJSON/JsonParser.cs | 11 +- fastJSON/JsonSerializer.cs | 28 ++-- fastJSON/fastJSON.csproj | 4 +- 7 files changed, 261 insertions(+), 156 deletions(-) diff --git a/Consoletest/Program.cs b/Consoletest/Program.cs index 1911e21..68a8b5e 100644 --- a/Consoletest/Program.cs +++ b/Consoletest/Program.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Data; +using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; @@ -171,19 +172,21 @@ namespace consoletest Console.WriteLine(); Console.Write("fastjson deserialize"); colclass c = CreateObject(); + var stopwatch = new Stopwatch(); for (int pp = 0; pp < tcount; pp++) { - DateTime st = DateTime.Now; colclass deserializedStore; string jsonText = null; + stopwatch.Restart(); jsonText = fastJSON.JSON.Instance.ToJSON(c); //Console.WriteLine(" size = " + jsonText.Length); for (int i = 0; i < count; i++) { deserializedStore = (colclass)fastJSON.JSON.Instance.ToObject(jsonText); } - Console.Write("\t" + DateTime.Now.Subtract(st).TotalMilliseconds); + stopwatch.Stop(); + Console.Write("\t" + stopwatch.ElapsedMilliseconds); } } @@ -192,15 +195,17 @@ namespace consoletest Console.WriteLine(); Console.Write("fastjson serialize"); colclass c = CreateObject(); + var stopwatch = new Stopwatch(); for (int pp = 0; pp < tcount; pp++) { - DateTime st = DateTime.Now; string jsonText = null; + stopwatch.Restart(); for (int i = 0; i < count; i++) { jsonText = fastJSON.JSON.Instance.ToJSON(c); } - Console.Write("\t" + DateTime.Now.Subtract(st).TotalMilliseconds); + stopwatch.Stop(); + Console.Write("\t" + stopwatch.ElapsedMilliseconds); } } @@ -209,20 +214,24 @@ namespace consoletest Console.WriteLine(); Console.Write("bin deserialize"); colclass c = CreateObject(); + var stopwatch = new Stopwatch(); for (int pp = 0; pp < tcount; pp++) { - DateTime st = DateTime.Now; BinaryFormatter bf = new BinaryFormatter(); MemoryStream ms = new MemoryStream(); + colclass deserializedStore = null; + stopwatch.Restart(); bf.Serialize(ms, c); - colclass deserializedStore = null; //Console.WriteLine(" size = " +ms.Length); for (int i = 0; i < count; i++) { + stopwatch.Stop(); // we stop then resume the stopwatch here so we don't factor in Seek()'s execution ms.Seek(0L, SeekOrigin.Begin); + stopwatch.Start(); deserializedStore = (colclass)bf.Deserialize(ms); } - Console.Write("\t" + DateTime.Now.Subtract(st).TotalMilliseconds); + stopwatch.Stop(); + Console.Write("\t" + stopwatch.ElapsedMilliseconds); } } @@ -230,17 +239,21 @@ namespace consoletest { Console.Write("\r\nbin serialize"); colclass c = CreateObject(); + var stopwatch = new Stopwatch(); for (int pp = 0; pp < tcount; pp++) { - DateTime st = DateTime.Now; BinaryFormatter bf = new BinaryFormatter(); MemoryStream ms = new MemoryStream(); + stopwatch.Restart(); for (int i = 0; i < count; i++) { + stopwatch.Stop(); // we stop then resume the stop watch here so we don't factor in the MemoryStream()'s execution ms = new MemoryStream(); + stopwatch.Start(); bf.Serialize(ms, c); } - Console.Write("\t" + DateTime.Now.Subtract(st).TotalMilliseconds); + stopwatch.Stop(); + Console.Write("\t" + stopwatch.ElapsedMilliseconds); } } diff --git a/Consoletest/consoletest.csproj b/Consoletest/consoletest.csproj index 1af547c..9652f6f 100644 --- a/Consoletest/consoletest.csproj +++ b/Consoletest/consoletest.csproj @@ -59,7 +59,6 @@ - diff --git a/Consoletest/dataobjects.cs b/Consoletest/dataobjects.cs index 8a77c3a..2631a4c 100644 --- a/Consoletest/dataobjects.cs +++ b/Consoletest/dataobjects.cs @@ -8,12 +8,14 @@ namespace consoletest #region [ data objects ] + [Serializable] public class baseclass { public string Name { get; set; } public string Code { get; set; } } + [Serializable] public class class1 : baseclass { public class1() { } @@ -26,6 +28,7 @@ namespace consoletest public Guid guid { get; set; } } + [Serializable] public class class2 : baseclass { public class2() { } @@ -44,6 +47,7 @@ namespace consoletest Female } + [Serializable] public class colclass { public colclass() diff --git a/fastJSON/JSON.cs b/fastJSON/JSON.cs index 452a822..81b1260 100644 --- a/fastJSON/JSON.cs +++ b/fastJSON/JSON.cs @@ -68,6 +68,7 @@ namespace fastJSON public sealed class JSON { + //static JSON() { Console.WriteLine("myPropInfo: {0}", System.Runtime.InteropServices.Marshal.SizeOf(typeof(myPropInfo)).ToString("X8")); } //public readonly static JSON Instance = new JSON(); [ThreadStatic] private static JSON _instance; @@ -229,39 +230,55 @@ namespace fastJSON #region [ JSON specific reflection ] + private enum myPropInfoType + { + Int, + Long, + String, + Bool, + DateTime, + Enum, + Guid, + + Array, + ByteArray, + Dictionary, + StringDictionary, +#if !SILVERLIGHT + Hashtable, + DataSet, + DataTable, +#endif +#if CUSTOMTYPE + Custom, +#endif + + Unknown, + }; + [Flags] + private enum myPropInfoFlags + { + Filled = 1<<0, + CanWrite = 1<<1, + Class = 1<<2, + ValueType = 1<<3, + GenericType = 1<<4, + }; private struct myPropInfo { - public bool filled; public Type pt; public Type bt; public Type changeType; - public bool isDictionary; - public bool isValueType; - public bool isGenericType; - public bool isArray; - public bool isByteArray; - public bool isGuid; -#if !SILVERLIGHT - public bool isDataSet; - public bool isDataTable; - public bool isHashtable; -#endif - public Reflection.GenericSetter setter; - public bool isEnum; - public bool isDateTime; - public Type[] GenericTypes; - public bool isInt; - public bool isLong; - public bool isString; - public bool isBool; - public bool isClass; - public Reflection.GenericGetter getter; - public bool isStringDictionary; - public string Name; -#if CUSTOMTYPE - public bool isCustomType; -#endif - public bool CanWrite; + public Reflection.GenericSetter setter; + public Reflection.GenericGetter getter; + public Type[] GenericTypes; + public string Name; + public myPropInfoType Type; + public myPropInfoFlags Flags; + + public bool IsClass { get { return (Flags & myPropInfoFlags.Class) != 0; } } + public bool IsValueType { get { return (Flags & myPropInfoFlags.ValueType) != 0; } } + public bool IsGenericType { get { return (Flags & myPropInfoFlags.GenericType) != 0; } } } SafeDictionary> _propertycache = new SafeDictionary>(); @@ -279,7 +296,7 @@ namespace fastJSON foreach (PropertyInfo p in pr) { myPropInfo d = CreateMyProp(p.PropertyType, p.Name); - d.CanWrite = p.CanWrite; + d.Flags |= myPropInfoFlags.CanWrite; d.setter = Reflection.CreateSetMethod(type, p); d.getter = Reflection.CreateGetMethod(type, p); sd.Add(p.Name, d); @@ -301,44 +318,55 @@ namespace fastJSON private myPropInfo CreateMyProp(Type t, string name) { myPropInfo d = new myPropInfo(); - d.filled = true; - d.CanWrite = true; - d.pt = t; - d.Name = name; - d.isDictionary = t.Name.Contains("Dictionary"); - if (d.isDictionary) - d.GenericTypes = t.GetGenericArguments(); - d.isValueType = t.IsValueType; - d.isGenericType = t.IsGenericType; - d.isArray = t.IsArray; - if (d.isArray) - d.bt = t.GetElementType(); - if (d.isGenericType) - d.bt = t.GetGenericArguments()[0]; - d.isByteArray = t == typeof(byte[]); - d.isGuid = (t == typeof(Guid) || t == typeof(Guid?)); + myPropInfoType d_type = myPropInfoType.Unknown; + myPropInfoFlags d_flags = myPropInfoFlags.Filled | myPropInfoFlags.CanWrite; + + if (t == typeof(int) || t == typeof(int?)) d_type = myPropInfoType.Int; + else if (t == typeof(long) || t == typeof(long?)) d_type = myPropInfoType.Long; + else if (t == typeof(string)) d_type = myPropInfoType.String; + else if (t == typeof(bool) || t == typeof(bool?)) d_type = myPropInfoType.Bool; + else if (t == typeof(DateTime) || t == typeof(DateTime?)) d_type = myPropInfoType.DateTime; + else if (t.IsEnum) d_type = myPropInfoType.Enum; + else if (t == typeof(Guid) || t == typeof(Guid?)) d_type = myPropInfoType.Guid; + else if (t.IsArray) + { + d.bt = t.GetElementType(); + if (t == typeof(byte[])) + d_type = myPropInfoType.ByteArray; + else + d_type = myPropInfoType.Array; + } + else if (t.Name.Contains("Dictionary")) + { + d.GenericTypes = t.GetGenericArguments(); + if(d.GenericTypes.Length > 0 && d.GenericTypes[0] == typeof(string)) + d_type = myPropInfoType.StringDictionary; + else + d_type = myPropInfoType.Dictionary; + } #if !SILVERLIGHT - d.isHashtable = t == typeof(Hashtable); - d.isDataSet = t == typeof(DataSet); - d.isDataTable = t == typeof(DataTable); + else if (t == typeof(Hashtable)) d_type = myPropInfoType.Hashtable; + else if (t == typeof(DataSet)) d_type = myPropInfoType.DataSet; + else if (t == typeof(DataTable)) d_type = myPropInfoType.DataTable; +#endif +#if CUSTOMTYPE + else if (IsTypeRegistered(t)) d_type = myPropInfoType.Custom; #endif - d.changeType = GetChangeType(t); - d.isEnum = t.IsEnum; - d.isDateTime = t == typeof(DateTime) || t == typeof(DateTime?); - d.isInt = t == typeof(int) || t == typeof(int?); - d.isLong = t == typeof(long) || t == typeof(long?); - d.isString = t == typeof(string); - d.isBool = t == typeof(bool) || t == typeof(bool?); - d.isClass = t.IsClass; + if (t.IsClass) d_flags |= myPropInfoFlags.Class; + if (t.IsValueType) d_flags |= myPropInfoFlags.ValueType; + if (t.IsGenericType) + { + d_flags |= myPropInfoFlags.GenericType; + d.bt = t.GetGenericArguments()[0]; + } - if (d.isDictionary && d.GenericTypes.Length > 0 && d.GenericTypes[0] == typeof(string)) - d.isStringDictionary = true; + d.pt = t; + d.Name = name; + d.changeType = GetChangeType(t); + d.Type = d_type; + d.Flags = d_flags; -#if CUSTOMTYPE - if (IsTypeRegistered(t)) - d.isCustomType = true; -#endif return d; } @@ -469,74 +497,59 @@ namespace fastJSON myPropInfo pi; if (props.TryGetValue(name, out pi) == false) continue; - if (pi.filled && pi.CanWrite) + if ((pi.Flags & (myPropInfoFlags.Filled|myPropInfoFlags.CanWrite)) != 0) { object v = d[name]; if (v != null) { - object oset = null; - - if (pi.isInt) - oset = (int)((long)v); -#if CUSTOMTYPE - else if (pi.isCustomType) - oset = CreateCustom((string)v, pi.pt); -#endif - else if (pi.isLong) - oset = (long)v; - - else if (pi.isString) - oset = (string)v; - - else if (pi.isBool) - oset = (bool)v; - - else if (pi.isGenericType && pi.isValueType == false && pi.isDictionary == false && v is List) - oset = CreateGenericList((List)v, pi.pt, pi.bt, globaltypes); - - else if (pi.isByteArray) - oset = Convert.FromBase64String((string)v); - - else if (pi.isArray && pi.isValueType == false) - oset = CreateArray((List)v, pi.pt, pi.bt, globaltypes); - - else if (pi.isGuid) - oset = CreateGuid((string)v); + object oset = null; + + switch (pi.Type) + { + case myPropInfoType.Int: oset = (int)((long)v); break; + case myPropInfoType.Long: oset = (long)v; break; + case myPropInfoType.String: oset = (string)v; break; + case myPropInfoType.Bool: oset = (bool)v; break; + case myPropInfoType.DateTime: oset = CreateDateTime((string)v); break; + case myPropInfoType.Enum: oset = CreateEnum(pi.pt, (string)v); break; + case myPropInfoType.Guid: oset = CreateGuid((string)v); break; + + case myPropInfoType.Array: + if(!pi.IsValueType) + oset = CreateArray((List)v, pi.pt, pi.bt, globaltypes); + // what about 'else'? + break; + case myPropInfoType.ByteArray: oset = Convert.FromBase64String((string)v); break; #if !SILVERLIGHT - else if (pi.isDataSet) - oset = CreateDataset((Dictionary)v, globaltypes); - - else if (pi.isDataTable) - oset = this.CreateDataTable((Dictionary)v, globaltypes); + case myPropInfoType.DataSet: oset = CreateDataset((Dictionary)v, globaltypes); break; + case myPropInfoType.DataTable: oset = this.CreateDataTable((Dictionary)v, globaltypes); break; + case myPropInfoType.Hashtable: // same case as Dictionary #endif - - else if (pi.isStringDictionary) - oset = CreateStringKeyDictionary((Dictionary)v, pi.pt, pi.GenericTypes, globaltypes); -#if !SILVERLIGHT - else if (pi.isDictionary || pi.isHashtable) -#else - else if (pi.isDictionary) + case myPropInfoType.Dictionary: oset = CreateDictionary((List)v, pi.pt, pi.GenericTypes, globaltypes); break; + case myPropInfoType.StringDictionary: oset = CreateStringKeyDictionary((Dictionary)v, pi.pt, pi.GenericTypes, globaltypes); break; +#if CUSTOMTYPE + case myPropInfoType.Custom: oset = CreateCustom((string)v, pi.pt); break; #endif - oset = CreateDictionary((List)v, pi.pt, pi.GenericTypes, globaltypes); - - else if (pi.isEnum) - oset = CreateEnum(pi.pt, (string)v); - - else if (pi.isDateTime) - oset = CreateDateTime((string)v); + default: + { + if (pi.IsGenericType && pi.IsValueType == false && v is List) + oset = CreateGenericList((List)v, pi.pt, pi.bt, globaltypes); - else if (pi.isClass && v is Dictionary) - oset = ParseDictionary((Dictionary)v, globaltypes, pi.pt, pi.getter(o)); + else if (pi.IsClass && v is Dictionary) + oset = ParseDictionary((Dictionary)v, globaltypes, pi.pt, pi.getter(o)); - else if (pi.isValueType) - oset = ChangeType(v, pi.changeType); + else if (v is List) + oset = CreateArray((List)v, pi.pt, typeof(object), globaltypes); - else if (v is List) - oset = CreateArray((List)v, pi.pt, typeof(object), globaltypes); + else if (pi.IsValueType) + oset = ChangeType(v, pi.changeType); - else - oset = v; + else + oset = v; + } + break; + } o = pi.setter(o, oset); } @@ -566,6 +579,72 @@ namespace fastJSON } } + static int CreateInteger(out int num, string s, int index, int count) + { + num = 0; + bool neg = false; + for (int x = 0; x < count; x++, index++) + { + char cc = s[index]; + + if (cc == '-') + neg = true; + else if (cc == '+') + neg = false; + else + { + num *= 10; + num += (int)(cc - '0'); + } + } + if(neg) num = -num; + + return num; + } + static long CreateInteger(out long num, string s, int index, int count) + { + num = 0; + bool neg = false; + for (int x = 0; x < count; x++, index++) + { + char cc = s[index]; + + if (cc == '-') + neg = true; + else if (cc == '+') + neg = false; + else + { + num *= 10; + num += (int)(cc - '0'); + } + } + if (neg) num = -num; + + return num; + } + internal static long CreateInteger(out long num, char[] s, int index, int count) + { + num = 0; + bool neg = false; + for (int x = 0; x < count; x++, index++) + { + char cc = s[index]; + + if (cc == '-') + neg = true; + else if (cc == '+') + neg = false; + else + { + num *= 10; + num += (int)(cc - '0'); + } + } + if (neg) num = -num; + + return num; + } private long CreateLong(string s) { long num = 0; @@ -609,14 +688,21 @@ namespace fastJSON bool utc = false; // 0123456789012345678 // datetime format = yyyy-MM-dd HH:mm:ss - int year = (int)CreateLong(value.Substring(0, 4)); - int month = (int)CreateLong(value.Substring(5, 2)); - int day = (int)CreateLong(value.Substring(8, 2)); - int hour = (int)CreateLong(value.Substring(11, 2)); - int min = (int)CreateLong(value.Substring(14, 2)); - int sec = (int)CreateLong(value.Substring(17, 2)); - - if (value.EndsWith("Z")) + int year;// = (int)CreateLong(value.Substring(0, 4)); + int month;// = (int)CreateLong(value.Substring(5, 2)); + int day;// = (int)CreateLong(value.Substring(8, 2)); + int hour;// = (int)CreateLong(value.Substring(11, 2)); + int min;// = (int)CreateLong(value.Substring(14, 2)); + int sec;// = (int)CreateLong(value.Substring(17, 2)); + CreateInteger(out year, value, 0, 4); + CreateInteger(out month, value, 5, 2); + CreateInteger(out day, value, 8, 2); + CreateInteger(out hour, value, 11, 2); + CreateInteger(out min, value, 14, 2); + CreateInteger(out sec, value, 17, 2); + + //if (value.EndsWith("Z")) + if (value[value.Length-1] == 'Z') utc = true; if (_params.UseUTCDateTime == false && utc == false) diff --git a/fastJSON/JsonParser.cs b/fastJSON/JsonParser.cs index 3c2abdd..929ab73 100644 --- a/fastJSON/JsonParser.cs +++ b/fastJSON/JsonParser.cs @@ -305,10 +305,13 @@ namespace fastJSON break; } while (true); - string s = new string(json, startIndex, index - startIndex); - if (dec) - return double.Parse(s,NumberFormatInfo.InvariantInfo); - return CreateLong(s); + if (dec) + { + string s = new string(json, startIndex, index - startIndex); + return double.Parse(s, NumberFormatInfo.InvariantInfo); + } + long num; + return JSON.CreateInteger(out num, json, startIndex, index - startIndex); } private Token LookAhead() diff --git a/fastJSON/JsonSerializer.cs b/fastJSON/JsonSerializer.cs index 50c8c9d..a3611c5 100644 --- a/fastJSON/JsonSerializer.cs +++ b/fastJSON/JsonSerializer.cs @@ -40,11 +40,11 @@ namespace fastJSON { if (pendingSeparator) sb.Append(','); pendingSeparator = true; - sb.Append("\""); + sb.Append('\"'); sb.Append(kv.Key); sb.Append("\":\""); sb.Append(kv.Value); - sb.Append("\""); + sb.Append('\"'); } sb.Append("},"); sb.Append(_output.ToString()); @@ -150,23 +150,23 @@ namespace fastJSON if (_params.UseUTCDateTime) dt = dateTime.ToUniversalTime(); - _output.Append("\""); + _output.Append('\"'); _output.Append(dt.Year.ToString("0000", NumberFormatInfo.InvariantInfo)); - _output.Append("-"); + _output.Append('-'); _output.Append(dt.Month.ToString("00", NumberFormatInfo.InvariantInfo)); - _output.Append("-"); + _output.Append('-'); _output.Append(dt.Day.ToString("00", NumberFormatInfo.InvariantInfo)); - _output.Append(" "); + _output.Append(' '); _output.Append(dt.Hour.ToString("00", NumberFormatInfo.InvariantInfo)); - _output.Append(":"); + _output.Append(':'); _output.Append(dt.Minute.ToString("00", NumberFormatInfo.InvariantInfo)); - _output.Append(":"); + _output.Append(':'); _output.Append(dt.Second.ToString("00", NumberFormatInfo.InvariantInfo)); if (_params.UseUTCDateTime) - _output.Append("Z"); + _output.Append('Z'); - _output.Append("\""); + _output.Append('\"'); } #if !SILVERLIGHT @@ -231,7 +231,7 @@ namespace fastJSON bool tablesep = false; foreach (DataTable table in ds.Tables) { - if (tablesep) _output.Append(","); + if (tablesep) _output.Append(','); tablesep = true; WriteDataTableData(table); } @@ -248,7 +248,7 @@ namespace fastJSON bool rowseparator = false; foreach (DataRow row in table.Rows) { - if (rowseparator) _output.Append(","); + if (rowseparator) _output.Append(','); rowseparator = true; _output.Append('['); @@ -290,12 +290,12 @@ namespace fastJSON { if (_TypesWritten == false) { - _output.Append("{"); + _output.Append('{'); _before = _output; _output = new StringBuilder(); } else - _output.Append("{"); + _output.Append('{'); } _TypesWritten = true; _current_depth++; diff --git a/fastJSON/fastJSON.csproj b/fastJSON/fastJSON.csproj index 9eabd29..ba0c013 100644 --- a/fastJSON/fastJSON.csproj +++ b/fastJSON/fastJSON.csproj @@ -48,7 +48,7 @@ bin\Debug\ prompt 4 - -CUSTOMTYPE + CUSTOMTYPE full @@ -74,7 +74,7 @@ - +