如何检查两个Span <t>是否相交?

时间:2018-08-21 03:29:35

标签: c#

考虑以下功能:

public static bool TryToDoStuff(ReadOnlySpan<byte> input, Span<byte> destination) {
    ...
}

此函数根据destination的内容返回是否能够在input上执行操作。

我想检查内存区域是否被 inputdestination“包裹”,并且如果相交,则抛出异常,因为这会破坏{ {1}}的数据。 我该如何做(没有反射或不安全的代码)?

我知道我可以编写一些xmldoc并警告用户这些参数不应相交,但这是一个穷人的解决方案。

编辑:对于那些要求示例的人,沃兹纳的示例很重要。

input

3 个答案:

答案 0 :(得分:3)

有一种使用System.Runtime.CompilerServices.Unsafe NuGet程序包的方法。它提供了ByteOffsetSizeOf之类的低级方法。

使用这些方法,您可以编写以下方法:

public static bool Intersects<T>(ReadOnlySpan<T> a, ReadOnlySpan<T> b) 
{
    var elementSize = Unsafe.SizeOf<T>();
    var distance = (long)Unsafe.ByteOffset<T>(ref MemoryMarshal.GetReference(a), ref MemoryMarshal.GetReference(b));
    if (distance < 0) 
    {
        return -distance < b.Length * elementSize;
    }
    else if (distance > 0) 
    {
        return distance < a.Length * elementSize;
    }
    return true;
}

此方法确定每个跨度中第一个元素之间的距离(以字节为单位)。然后确定距离是否小于跨度中的项数乘以跨度中单个元素的大小(以字节为单位)。

通过使用Unsafe.SizeOf<T>,我们甚至允许在非原始类型上使用此方法。诸如字符串和类之类的引用类型是本机整数(IntPtr.Size)的大小。

下面一些表明该方法有效的测试用例:

// On arrays
Span<byte> firstArray = new byte[10];
Span<byte> secondArray = new byte[10];
Intersects<byte>(firstArray.Slice(5, 5), firstArray.Slice(3, 5)); // true
Intersects<byte>(firstArray.Slice(5, 5), secondArray.Slice(3, 5)); // false

// And on stackallocated memory
Span<byte> firstStack = stackalloc byte[10];
Span<byte> secondStack = stackalloc byte[10];
Intersects<byte>(firstStack.Slice(5, 5), firstStack.Slice(3, 5)); // true
Intersects<byte>(firstStack.Slice(5, 5), secondStack.Slice(3, 5)); // false

注意:System.Runtime.CompilerServices.Unsafe软件包需要使用ref-returns,这是一个仅从C#7开始可用的功能

答案 1 :(得分:2)

我在dotnet / corefx存储库上创建了一个问题,其中一位贡献者发布了此链接:

https://docs.microsoft.com/en-us/dotnet/api/system.memoryextensions.overlaps?view=netcore-2.1

是的,有一个优雅,简洁,安全且框架内的解决方案。

答案 2 :(得分:0)

“不使用反射或不安全的代码”-不可能,因为_pointer的{​​{1}}属性没有以任何方式公开公开:

https://github.com/dotnet/corefx/blob/ab27e64721496ab7404fd52d8d7720db572fc2f4/src/Common/src/CoreLib/System/Span.Fast.cs#L30