C#: Optimize parsing of some primitive and wrapper types
diff --git a/csharp/src/Google.Protobuf/FieldCodec.cs b/csharp/src/Google.Protobuf/FieldCodec.cs
index ebd00b7..7689964 100644
--- a/csharp/src/Google.Protobuf/FieldCodec.cs
+++ b/csharp/src/Google.Protobuf/FieldCodec.cs
@@ -507,7 +507,7 @@
{
var nestedCodec = WrapperCodecs.GetCodec<T>();
return new FieldCodec<T?>(
- input => WrapperCodecs.Read<T>(input, nestedCodec),
+ WrapperCodecs.GetReader<T>(),
(output, value) => WrapperCodecs.Write<T>(output, value.Value, nestedCodec),
(CodedInputStream i, ref T? v) => v = WrapperCodecs.Read<T>(i, nestedCodec),
(ref T? v, T? v2) => { if (v2.HasValue) { v = v2; } return v.HasValue; },
@@ -539,6 +539,22 @@
{ typeof(ByteString), ForBytes(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
};
+ private static readonly Dictionary<System.Type, Func<object>> Readers = new Dictionary<System.Type, Func<object>>
+ {
+ // TODO: Provide more optimized readers.
+ { typeof(bool), null },
+ { typeof(int), null },
+ { typeof(long), () => (Func<CodedInputStream, long?>)CodedInputStream.ReadInt64Wrapper },
+ { typeof(uint), null },
+ { typeof(ulong), null },
+ { typeof(float), null },
+ { typeof(double), () => BitConverter.IsLittleEndian ?
+ (Func<CodedInputStream, double?>)CodedInputStream.ReadDoubleWrapperLittleEndian :
+ (Func<CodedInputStream, double?>)CodedInputStream.ReadDoubleWrapperBigEndian },
+ { typeof(string), null },
+ { typeof(ByteString), null },
+ };
+
/// <summary>
/// Returns a field codec which effectively wraps a value of type T in a message.
///
@@ -553,6 +569,23 @@
return (FieldCodec<T>) value;
}
+ internal static Func<CodedInputStream, T?> GetReader<T>() where T : struct
+ {
+ Func<object> value;
+ if (!Readers.TryGetValue(typeof(T), out value))
+ {
+ throw new InvalidOperationException("Invalid type argument requested for wrapper reader: " + typeof(T));
+ }
+ if (value == null)
+ {
+ // Return default unoptimized reader for the wrapper type.
+ var nestedCoded = GetCodec<T>();
+ return input => Read<T>(input, nestedCoded);
+ }
+ // Return optimized read for the wrapper type.
+ return (Func<CodedInputStream, T?>)value();
+ }
+
internal static T Read<T>(CodedInputStream input, FieldCodec<T> codec)
{
int length = input.ReadLength();