From b6e104f22f6baec437828014611a196f4cf72c4b Mon Sep 17 00:00:00 2001 From: mgravell <marc.gravell@gmail.com> Date: Thu, 4 Jul 2019 08:21:17 +0100 Subject: [PATCH] make use of Encoding.GetString(byte*, int) when available; poly-fill when not available (NET45); move related logic to extension class --- src/csharp/Grpc.Core.Api/Metadata.cs | 17 ++------- .../Grpc.Core.Api/Utils/EncodingExtensions.cs | 36 +++++++++++++++++++ src/csharp/Grpc.Core/Internal/MarshalUtils.cs | 23 ++++-------- 3 files changed, 45 insertions(+), 31 deletions(-) create mode 100644 src/csharp/Grpc.Core.Api/Utils/EncodingExtensions.cs diff --git a/src/csharp/Grpc.Core.Api/Metadata.cs b/src/csharp/Grpc.Core.Api/Metadata.cs index 7a04a2ee859..cd1ea3b4676 100644 --- a/src/csharp/Grpc.Core.Api/Metadata.cs +++ b/src/csharp/Grpc.Core.Api/Metadata.cs @@ -19,7 +19,7 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; -using System.Text.RegularExpressions; +using Grpc.Core.Api.Utils; using Grpc.Core.Utils; @@ -364,20 +364,7 @@ namespace Grpc.Core } else { - string s; - if (length == 0) - { - s = ""; - } - else - { - int charCount = EncodingASCII.GetCharCount(source, length); - s = new string('\0', charCount); - fixed (char* cPtr = s) - { - EncodingASCII.GetChars(source, length, cPtr, charCount); - } - } + string s = length == 0 ? "" : EncodingASCII.GetString(source, length); return new Entry(key, s, null); } } diff --git a/src/csharp/Grpc.Core.Api/Utils/EncodingExtensions.cs b/src/csharp/Grpc.Core.Api/Utils/EncodingExtensions.cs new file mode 100644 index 00000000000..ef38baf5cc4 --- /dev/null +++ b/src/csharp/Grpc.Core.Api/Utils/EncodingExtensions.cs @@ -0,0 +1,36 @@ +using System; +using System.Text; + +namespace Grpc.Core.Api.Utils +{ + + internal static class EncodingExtensions + { +#if NET45 // back-fill over a method missing in NET45 + /// <summary> + /// Converts <c>byte*</c> pointing to an encoded byte array to a <c>string</c> using the provided <c>Encoding</c>. + /// </summary> + public static unsafe string GetString(this Encoding encoding, byte* source, int byteCount) + { + if (byteCount == 0) return ""; // most callers will have already checked, but: make sure + + // allocate a right-sized string and decode into it + int charCount = encoding.GetCharCount(source, byteCount); + string s = new string('\0', charCount); + fixed (char* cPtr = s) + { + encoding.GetChars(source, byteCount, cPtr, charCount); + } + return s; + } +#endif + /// <summary> + /// Converts <c>IntPtr</c> pointing to a encoded byte array to a <c>string</c> using the provided <c>Encoding</c>. + /// </summary> + public static unsafe string GetString(this Encoding encoding, IntPtr ptr, int len) + { + return len == 0 ? "" : encoding.GetString((byte*)ptr.ToPointer(), len); + } + } + +} diff --git a/src/csharp/Grpc.Core/Internal/MarshalUtils.cs b/src/csharp/Grpc.Core/Internal/MarshalUtils.cs index 54b4370935d..313e2b5c9d7 100644 --- a/src/csharp/Grpc.Core/Internal/MarshalUtils.cs +++ b/src/csharp/Grpc.Core/Internal/MarshalUtils.cs @@ -17,8 +17,9 @@ #endregion using System; -using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using System.Text; +using Grpc.Core.Api.Utils; namespace Grpc.Core.Internal { @@ -32,22 +33,10 @@ namespace Grpc.Core.Internal /// <summary> /// Converts <c>IntPtr</c> pointing to a UTF-8 encoded byte array to <c>string</c>. /// </summary> - public static unsafe string PtrToStringUTF8(IntPtr ptr, int len) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string PtrToStringUTF8(IntPtr ptr, int len) { - if (len == 0) - { - return ""; - } - - // allocate a right-sized string and decode into it - byte* source = (byte*)ptr.ToPointer(); - int charCount = EncodingUTF8.GetCharCount(source, len); - string s = new string('\0', charCount); - fixed(char* cPtr = s) - { - EncodingUTF8.GetChars(source, len, cPtr, charCount); - } - return s; + return EncodingUTF8.GetString(ptr, len); } /// <summary> @@ -66,6 +55,7 @@ namespace Grpc.Core.Internal /// <summary> /// Returns the maximum number of bytes required to encode a given string. /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetMaxByteCountUTF8(string str) { return EncodingUTF8.GetMaxByteCount(str.Length); @@ -74,6 +64,7 @@ namespace Grpc.Core.Internal /// <summary> /// Returns the actual number of bytes required to encode a given string. /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int GetByteCountUTF8(string str) { return EncodingUTF8.GetByteCount(str);