Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit dadf537

Browse files
committed
Switch to slightly better performing TypeCode
1 parent 1e0d765 commit dadf537

File tree

3 files changed

+160
-102
lines changed

3 files changed

+160
-102
lines changed

src/ServiceStack.Text/Common/JsWriter.cs

Lines changed: 75 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
using System.Collections;
33
using System.Collections.Generic;
44
using System.IO;
5-
using System.Reflection;
6-
using System.Linq;
7-
85
using ServiceStack.Text.Json;
96
using ServiceStack.Text.Jsv;
107

@@ -87,19 +84,25 @@ internal static void WriteItemSeperatorIfRanOnce(TextWriter writer, ref bool ran
8784

8885
internal static bool ShouldUseDefaultToStringMethod(Type type)
8986
{
90-
return type == typeof(byte) || type == typeof(byte?)
91-
|| type == typeof(short) || type == typeof(short?)
92-
|| type == typeof(ushort) || type == typeof(ushort?)
93-
|| type == typeof(int) || type == typeof(int?)
94-
|| type == typeof(uint) || type == typeof(uint?)
95-
|| type == typeof(long) || type == typeof(long?)
96-
|| type == typeof(ulong) || type == typeof(ulong?)
97-
|| type == typeof(bool) || type == typeof(bool?)
98-
|| type == typeof(DateTime) || type == typeof(DateTime?)
99-
|| type == typeof(Guid) || type == typeof(Guid?)
100-
|| type == typeof(float) || type == typeof(float?)
101-
|| type == typeof(double) || type == typeof(double?)
102-
|| type == typeof(decimal) || type == typeof(decimal?);
87+
var underlyingType = Nullable.GetUnderlyingType(type) ?? type;
88+
switch (underlyingType.GetTypeCode())
89+
{
90+
case TypeCode.SByte:
91+
case TypeCode.Byte:
92+
case TypeCode.Int16:
93+
case TypeCode.UInt16:
94+
case TypeCode.Int32:
95+
case TypeCode.UInt32:
96+
case TypeCode.Int64:
97+
case TypeCode.UInt64:
98+
case TypeCode.Single:
99+
case TypeCode.Double:
100+
case TypeCode.Decimal:
101+
case TypeCode.DateTime:
102+
return true;
103+
}
104+
105+
return underlyingType == typeof(Guid);
103106
}
104107

105108
public static ITypeSerializer GetTypeSerializer<TSerializer>()
@@ -171,71 +174,77 @@ public JsWriter()
171174

172175
public WriteObjectDelegate GetValueTypeToStringMethod(Type type)
173176
{
174-
if (type == typeof(char) || type == typeof(char?))
175-
return Serializer.WriteChar;
176-
if (type == typeof(int) || type == typeof(int?))
177-
return Serializer.WriteInt32;
178-
if (type == typeof(long) || type == typeof(long?))
179-
return Serializer.WriteInt64;
180-
if (type == typeof(ulong) || type == typeof(ulong?))
181-
return Serializer.WriteUInt64;
182-
if (type == typeof(uint) || type == typeof(uint?))
183-
return Serializer.WriteUInt32;
177+
var underlyingType = Nullable.GetUnderlyingType(type);
178+
var isNullable = underlyingType != null;
179+
if (underlyingType == null)
180+
underlyingType = type;
184181

185-
if (type == typeof(byte) || type == typeof(byte?))
186-
return Serializer.WriteByte;
187-
188-
if (type == typeof(short) || type == typeof(short?))
189-
return Serializer.WriteInt16;
190-
if (type == typeof(ushort) || type == typeof(ushort?))
191-
return Serializer.WriteUInt16;
182+
if (!underlyingType.IsEnum())
183+
{
184+
var typeCode = underlyingType.GetTypeCode();
192185

193-
if (type == typeof(bool) || type == typeof(bool?))
194-
return Serializer.WriteBool;
186+
if (typeCode == TypeCode.Char)
187+
return Serializer.WriteChar;
188+
if (typeCode == TypeCode.Int32)
189+
return Serializer.WriteInt32;
190+
if (typeCode == TypeCode.Int64)
191+
return Serializer.WriteInt64;
192+
if (typeCode == TypeCode.UInt64)
193+
return Serializer.WriteUInt64;
194+
if (typeCode == TypeCode.UInt32)
195+
return Serializer.WriteUInt32;
195196

196-
if (type == typeof(DateTime))
197-
return Serializer.WriteDateTime;
197+
if (typeCode == TypeCode.Byte)
198+
return Serializer.WriteByte;
198199

199-
if (type == typeof(DateTime?))
200-
return Serializer.WriteNullableDateTime;
200+
if (typeCode == TypeCode.Int16)
201+
return Serializer.WriteInt16;
202+
if (typeCode == TypeCode.UInt16)
203+
return Serializer.WriteUInt16;
201204

202-
if (type == typeof(DateTimeOffset))
203-
return Serializer.WriteDateTimeOffset;
205+
if (typeCode == TypeCode.Boolean)
206+
return Serializer.WriteBool;
204207

205-
if (type == typeof(DateTimeOffset?))
206-
return Serializer.WriteNullableDateTimeOffset;
208+
if (typeCode == TypeCode.Single)
209+
return Serializer.WriteFloat;
207210

208-
if (type == typeof(TimeSpan))
209-
return Serializer.WriteTimeSpan;
211+
if (typeCode == TypeCode.Double)
212+
return Serializer.WriteDouble;
210213

211-
if (type == typeof(TimeSpan?))
212-
return Serializer.WriteNullableTimeSpan;
214+
if (typeCode == TypeCode.Decimal)
215+
return Serializer.WriteDecimal;
213216

214-
if (type == typeof(Guid))
215-
return Serializer.WriteGuid;
217+
if (typeCode == TypeCode.DateTime)
218+
if (isNullable)
219+
return Serializer.WriteNullableDateTime;
220+
else
221+
return Serializer.WriteDateTime;
216222

217-
if (type == typeof(Guid?))
218-
return Serializer.WriteNullableGuid;
223+
if (type == typeof(DateTimeOffset))
224+
return Serializer.WriteDateTimeOffset;
219225

220-
if (type == typeof(float) || type == typeof(float?))
221-
return Serializer.WriteFloat;
226+
if (type == typeof(DateTimeOffset?))
227+
return Serializer.WriteNullableDateTimeOffset;
222228

223-
if (type == typeof(double) || type == typeof(double?))
224-
return Serializer.WriteDouble;
229+
if (type == typeof(TimeSpan))
230+
return Serializer.WriteTimeSpan;
225231

226-
if (type == typeof(decimal) || type == typeof(decimal?))
227-
return Serializer.WriteDecimal;
232+
if (type == typeof(TimeSpan?))
233+
return Serializer.WriteNullableTimeSpan;
228234

229-
if (type.IsUnderlyingEnum())
230-
return type.FirstAttribute<FlagsAttribute>() != null
231-
? (WriteObjectDelegate)Serializer.WriteEnumFlags
232-
: Serializer.WriteEnum;
235+
if (type == typeof(Guid))
236+
return Serializer.WriteGuid;
233237

234-
Type nullableType;
235-
if ((nullableType = Nullable.GetUnderlyingType(type)) != null && nullableType.IsEnum())
236-
return nullableType.FirstAttribute<FlagsAttribute>() != null
237-
? (WriteObjectDelegate)Serializer.WriteEnumFlags
238-
: Serializer.WriteEnum;
238+
if (type == typeof(Guid?))
239+
return Serializer.WriteNullableGuid;
240+
}
241+
else
242+
{
243+
if (underlyingType.IsEnum())
244+
return type.FirstAttribute<FlagsAttribute>() != null
245+
? (WriteObjectDelegate)Serializer.WriteEnumFlags
246+
: Serializer.WriteEnum;
247+
}
239248

240249
if (type.HasInterface(typeof(IFormattable)))
241250
return Serializer.WriteFormattableObjectString;

src/ServiceStack.Text/TextExtensions.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
using System;
1414
using System.Collections.Generic;
1515
using ServiceStack.Text;
16-
using ServiceStack.Text.Common;
1716

1817
namespace ServiceStack
1918
{
@@ -22,25 +21,25 @@ public static class TextExtensions
2221
public static string ToCsvField(this string text)
2322
{
2423
return string.IsNullOrEmpty(text) || !CsvWriter.HasAnyEscapeChars(text)
25-
? text
26-
: string.Concat
27-
(
28-
CsvConfig.ItemDelimiterString,
29-
text.Replace(CsvConfig.ItemDelimiterString, CsvConfig.EscapedItemDelimiterString),
30-
CsvConfig.ItemDelimiterString
31-
);
24+
? text
25+
: string.Concat
26+
(
27+
CsvConfig.ItemDelimiterString,
28+
text.Replace(CsvConfig.ItemDelimiterString, CsvConfig.EscapedItemDelimiterString),
29+
CsvConfig.ItemDelimiterString
30+
);
3231
}
3332

3433
public static object ToCsvField(this object text)
3534
{
3635
return text == null || !CsvWriter.HasAnyEscapeChars(text.ToString())
37-
? text
38-
: string.Concat
39-
(
40-
CsvConfig.ItemDelimiterString,
41-
text.ToString().Replace(CsvConfig.ItemDelimiterString, CsvConfig.EscapedItemDelimiterString),
42-
CsvConfig.ItemDelimiterString
43-
);
36+
? text
37+
: string.Concat
38+
(
39+
CsvConfig.ItemDelimiterString,
40+
text.ToString().Replace(CsvConfig.ItemDelimiterString, CsvConfig.EscapedItemDelimiterString),
41+
CsvConfig.ItemDelimiterString
42+
);
4443
}
4544

4645
public static string FromCsvField(this string text)

tests/ServiceStack.Text.Tests/Support/BenchmarkTests.cs

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -138,32 +138,82 @@ internal static bool TestGenericType()
138138
|| typeof(T) != typeof(double) || typeof(T) != typeof(double?)
139139
|| typeof(T) != typeof(decimal) || typeof(T) != typeof(decimal?);
140140
}
141+
142+
internal static bool TestTypeCode()
143+
{
144+
var underlyingType = Nullable.GetUnderlyingType(type) ?? type;
145+
switch (underlyingType.GetTypeCode())
146+
{
147+
case TypeCode.SByte:
148+
case TypeCode.Byte:
149+
case TypeCode.Int16:
150+
case TypeCode.UInt16:
151+
case TypeCode.Int32:
152+
case TypeCode.UInt32:
153+
case TypeCode.Int64:
154+
case TypeCode.UInt64:
155+
case TypeCode.Single:
156+
case TypeCode.Double:
157+
case TypeCode.Decimal:
158+
case TypeCode.DateTime:
159+
return true;
160+
}
161+
162+
return underlyingType == typeof(Guid);
163+
}
141164
}
142165

166+
[Test]
167+
public void TestVarOrGenericType()
168+
{
169+
var matchingTypesCount = 0;
143170

144-
[Test]
145-
public void TestVarOrGenericType()
146-
{
147-
var matchingTypesCount = 0;
171+
CompareMultipleRuns(
172+
"With var type",
173+
() =>
174+
{
175+
if (RuntimeType<BenchmarkTests>.TestVarType())
176+
{
177+
matchingTypesCount++;
178+
}
179+
},
180+
"With generic type",
181+
() =>
182+
{
183+
if (RuntimeType<BenchmarkTests>.TestGenericType())
184+
{
185+
matchingTypesCount++;
186+
}
187+
});
148188

149-
CompareMultipleRuns(
150-
"With var type",
151-
() => {
152-
if (RuntimeType<BenchmarkTests>.TestVarType())
153-
{
154-
matchingTypesCount++;
155-
}
156-
},
157-
"With generic type",
158-
() => {
159-
if (RuntimeType<BenchmarkTests>.TestGenericType())
160-
{
161-
matchingTypesCount++;
162-
}
163-
});
189+
Console.WriteLine(matchingTypesCount);
190+
}
164191

165-
Console.WriteLine(matchingTypesCount);
166-
}
192+
[Test]
193+
public void TestGenericTypeOrTypeCode()
194+
{
195+
var matchingTypesCount = 0;
196+
197+
CompareMultipleRuns(
198+
"With type code",
199+
() =>
200+
{
201+
if (RuntimeType<BenchmarkTests>.TestTypeCode())
202+
{
203+
matchingTypesCount++;
204+
}
205+
},
206+
"With generic type",
207+
() =>
208+
{
209+
if (RuntimeType<BenchmarkTests>.TestGenericType())
210+
{
211+
matchingTypesCount++;
212+
}
213+
});
214+
215+
Console.WriteLine(matchingTypesCount);
216+
}
167217

168218
[Test]
169219
public void Test_for_list_enumeration()

0 commit comments

Comments
 (0)