move WellKnownStrings to top-level file; add tests; refactor

pull/19511/head
mgravell 6 years ago
parent 9967e42a7f
commit 3ab3f5e586
  1. 46
      src/csharp/Grpc.Core.Tests/Internal/WellKnownStringsTest.cs
  2. 33
      src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
  3. 66
      src/csharp/Grpc.Core/Internal/WellKnownStrings.cs

@ -0,0 +1,46 @@
using System.Text;
using Grpc.Core.Internal;
using NUnit.Framework;
namespace Grpc.Core.Tests.Internal
{
public class WellKnownStringsTest
{
[Test]
[TestCase("", true)]
[TestCase("u", false)]
[TestCase("us", false)]
[TestCase("use", false)]
[TestCase("user", false)]
[TestCase("user-", false)]
[TestCase("user-a", false)]
[TestCase("user-ag", false)]
[TestCase("user-age", false)]
[TestCase("user-agent", true)]
[TestCase("user-agent ", false)]
[TestCase("useragent ", false)]
[TestCase("User-Agent", false)]
[TestCase("sdlkfjlskjfdlkjs;lfdksflsdfkh skjdfh sdkfhskdhf skjfhk sdhjkjh", false)]
// test for endianness snafus (reversed in segments)
[TestCase("ega-resutn", false)]
public unsafe void TestWellKnownStrings(string input, bool expected)
{
// create a copy of the data; no cheating!
byte[] bytes = Encoding.ASCII.GetBytes(input);
fixed(byte* ptr = bytes)
{
string result = WellKnownStrings.TryIdentify(ptr, bytes.Length);
if (expected) Assert.AreEqual(input, result);
else Assert.IsNull(result);
if (expected)
{
// try again, and check we get the same instance
string again = WellKnownStrings.TryIdentify(ptr, bytes.Length);
Assert.AreSame(result, again);
}
}
}
}
}

@ -76,39 +76,6 @@ namespace Grpc.Core.Internal
return metadata;
}
private static class WellKnownStrings
{
// turn a string of ASCII-length 8 into a ulong using the CPUs current
// endianness; this allows us to do the same thing in TryIdentify,
// testing string prefixes (of length >= 8) in a single load/compare
private static unsafe ulong Thunk8(string value)
{
int byteCount = Encoding.ASCII.GetByteCount(value);
if (byteCount != 8) throw new ArgumentException(nameof(value));
ulong result = 0;
fixed (char* cPtr = value)
{
Encoding.ASCII.GetBytes(cPtr, value.Length, (byte*)&result, byteCount);
}
return result;
}
private static readonly ulong UserAgent = Thunk8("user-age");
public static unsafe string TryIdentify(byte* source, int length)
{
switch (length)
{
case 10:
// test the first 8 bytes via evilness
ulong first8 = *(ulong*)source;
if (first8 == UserAgent & source[8] == (byte)'n' & source[9] == (byte)'t')
return "user-agent";
break;
}
return null;
}
}
internal IntPtr Handle
{
get

@ -0,0 +1,66 @@
using System;
using System.Runtime.CompilerServices;
using System.Text;
namespace Grpc.Core.Internal
{
/// <summary>
/// Utility type for identifying "well-known" strings (i.e. headers/keys etc that
/// we expect to see frequently, and don't want to allocate lots of copies of)
/// </summary>
internal static class WellKnownStrings
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong Coerce64(byte* value)
{
return *(ulong*)value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint Coerce32(byte* value)
{
return *(uint*)value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ushort Coerce16(byte* value)
{
return *(ushort*)value;
}
/// <summary>
/// Test whether the provided byte sequence is recognized as a well-known string; if
/// so, return a shared instance of that string; otherwise, return null
/// </summary>
public static unsafe string TryIdentify(byte* source, int length)
{
// note: the logic here is hard-coded to constants for optimal processing;
// refer to an ASCII/hex converter (and remember to reverse **segments** for little-endian)
if (BitConverter.IsLittleEndian) // this is a JIT intrinsic; branch removal happens on modern runtimes
{
switch (length)
{
case 0: return "";
case 10:
switch(Coerce64(source))
{
case 0x6567612d72657375: return Coerce16(source + 8) == 0x746e ? "user-agent" : null;
}
break;
}
}
else
{
switch (length)
{
case 0: return "";
case 10:
switch (Coerce64(source))
{
case 0x757365722d616765: return Coerce16(source + 8) == 0x6e74 ? "user-agent" : null;
}
break;
}
}
return null;
}
}
}
Loading…
Cancel
Save